eCryptfs: fixed bug in cipher handling

Cipher was sometimes not treated properly, causing valid
requests belonging to eCryptfs to be treated as regular.

Change-Id: Iabfb93cc4c9e9e167901043482eb99613ed70343
Signed-off-by: Andrey Markovytch <andreym@codeaurora.org>
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
This commit is contained in:
Gilad Broner 2016-01-11 14:07:26 +02:00 committed by David Keitel
parent 53db8d989d
commit f50a4a1dc7
8 changed files with 127 additions and 113 deletions

View file

@ -470,8 +470,6 @@ out:
static void init_ecryption_parameters(bool *hw_crypt, bool *cipher_supported,
struct ecryptfs_crypt_stat *crypt_stat)
{
unsigned char final[2*ECRYPTFS_MAX_CIPHER_NAME_SIZE+1];
if (!hw_crypt || !cipher_supported)
return;
@ -480,9 +478,7 @@ static void init_ecryption_parameters(bool *hw_crypt, bool *cipher_supported,
if (get_events() && get_events()->is_cipher_supported_cb) {
*cipher_supported =
get_events()->is_cipher_supported_cb(
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode, final, sizeof(final)));
get_events()->is_cipher_supported_cb(crypt_stat);
if (*cipher_supported) {
/**
@ -809,12 +805,8 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
static int ecryptfs_generate_new_salt(struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = 0;
unsigned char final[2*ECRYPTFS_MAX_CIPHER_NAME_SIZE+1];
salt_size = ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode,
final, sizeof(final)));
salt_size = ecryptfs_get_salt_size_for_cipher(crypt_stat);
if (0 == salt_size)
return 0;

View file

@ -119,9 +119,10 @@ void ecryptfs_dump_hex(char *data, int bytes)
printk("\n");
}
void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher)
void ecryptfs_dump_salt_hex(char *data, int key_size,
const struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
size_t salt_size = ecryptfs_get_salt_size_for_cipher(crypt_stat);
if (0 == salt_size)
return;
@ -132,3 +133,18 @@ void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher)
ecryptfs_printk(KERN_DEBUG, "Decrypted session salt key:\n");
ecryptfs_dump_hex(data + key_size, salt_size);
}
void ecryptfs_dump_cipher(struct ecryptfs_crypt_stat *stat)
{
if (!stat)
return;
if (stat->cipher)
ecryptfs_printk(KERN_DEBUG,
"ecryptfs cipher is %s\n", stat->cipher);
if (stat->cipher_mode)
ecryptfs_printk(KERN_DEBUG, "ecryptfs cipher mode is %s\n",
stat->cipher_mode);
}

View file

@ -624,7 +624,10 @@ int ecryptfs_encrypt_and_encode_filename(
const char *name, size_t name_size);
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
void ecryptfs_dump_hex(char *data, int bytes);
void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher);
void ecryptfs_dump_salt_hex(char *data, int key_size,
const struct ecryptfs_crypt_stat *crypt_stat);
extern void ecryptfs_dump_cipher(struct ecryptfs_crypt_stat *stat);
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
int sg_size);
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
@ -779,16 +782,20 @@ void ecryptfs_freepage(struct page *page);
struct ecryptfs_events *get_events(void);
size_t ecryptfs_get_salt_size_for_cipher(const char *cipher);
size_t ecryptfs_get_salt_size_for_cipher(
const struct ecryptfs_crypt_stat *crypt_stat);
size_t ecryptfs_get_salt_size_for_cipher_mount(
const struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
size_t ecryptfs_get_key_size_to_enc_data(
struct ecryptfs_crypt_stat *crypt_stat);
const struct ecryptfs_crypt_stat *crypt_stat);
size_t ecryptfs_get_key_size_to_store_key(
struct ecryptfs_crypt_stat *crypt_stat);
const struct ecryptfs_crypt_stat *crypt_stat);
size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
const char *cipher);
const struct ecryptfs_crypt_stat *crypt_stat);
bool ecryptfs_check_space_for_salt(const size_t key_size,
const size_t salt_size);

View file

@ -1,6 +1,6 @@
/**
* eCryptfs: Linux filesystem encryption layer
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -42,7 +42,7 @@ void ecryptfs_free_events(void)
* The function returns a handle to be passed
* to unregister function.
*/
int ecryptfs_register_to_events(struct ecryptfs_events *ops)
int ecryptfs_register_to_events(const struct ecryptfs_events *ops)
{
int ret_value = 0;
@ -115,7 +115,7 @@ out:
* The caller must pass ecryptfs data, which was received in one
* of the callback invocations.
*/
bool ecryptfs_is_page_in_metadata(void *data, pgoff_t offset)
bool ecryptfs_is_page_in_metadata(const void *data, pgoff_t offset)
{
struct ecryptfs_crypt_stat *stat = NULL;
@ -145,7 +145,7 @@ end:
* Given two ecryptfs data, the function
* decides whether they are equal.
*/
inline bool ecryptfs_is_data_equal(void *data1, void *data2)
inline bool ecryptfs_is_data_equal(const void *data1, const void *data2)
{
/* pointer comparison*/
return data1 == data2;
@ -155,7 +155,7 @@ inline bool ecryptfs_is_data_equal(void *data1, void *data2)
* Given ecryptfs data, the function
* returns appropriate key size.
*/
size_t ecryptfs_get_key_size(void *data)
size_t ecryptfs_get_key_size(const void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
@ -173,49 +173,67 @@ size_t ecryptfs_get_key_size(void *data)
*
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_salt_size(void *data)
size_t ecryptfs_get_salt_size(const void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
unsigned char final[2*ECRYPTFS_MAX_CIPHER_NAME_SIZE+1];
if (!data) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_salt_size: invalid data parameter\n");
return 0;
}
stat = (struct ecryptfs_crypt_stat *)data;
return ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(stat->cipher,
stat->cipher_mode,
final, sizeof(final)));
return ecryptfs_get_salt_size_for_cipher(data);
}
/**
* Given ecryptfs data, the function
* returns appropriate cipher.
* Given ecryptfs data and cipher string, the function
* returns true if provided cipher and the one in ecryptfs match.
*/
const unsigned char *ecryptfs_get_cipher(void *data)
bool ecryptfs_cipher_match(const void *data,
const unsigned char *cipher, size_t cipher_size)
{
unsigned char final[2*ECRYPTFS_MAX_CIPHER_NAME_SIZE+1];
const unsigned char *ecryptfs_cipher = NULL;
struct ecryptfs_crypt_stat *stat = NULL;
if (!data) {
if (!data || !cipher) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_cipher: invalid data parameter\n");
return NULL;
return false;
}
if (!cipher_size || cipher_size > sizeof(final)) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_cipher: cipher_size\n");
return false;
}
stat = (struct ecryptfs_crypt_stat *)data;
return ecryptfs_get_full_cipher(stat->cipher, stat->cipher_mode,
ecryptfs_cipher = ecryptfs_get_full_cipher(stat->cipher,
stat->cipher_mode,
final, sizeof(final));
if (!ecryptfs_cipher) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_cipher: internal error while parsing cipher\n");
return false;
}
if (strcmp(ecryptfs_cipher, cipher)) {
if (ecryptfs_verbosity > 0)
ecryptfs_dump_cipher(stat);
return false;
}
return true;
}
/**
* Given ecryptfs data, the function
* returns file encryption key.
*/
const unsigned char *ecryptfs_get_key(void *data)
const unsigned char *ecryptfs_get_key(const void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
@ -233,7 +251,7 @@ const unsigned char *ecryptfs_get_key(void *data)
* Given ecryptfs data, the function
* returns file encryption salt.
*/
const unsigned char *ecryptfs_get_salt(void *data)
const unsigned char *ecryptfs_get_salt(const void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
@ -279,7 +297,7 @@ bool ecryptfs_check_space_for_salt(const size_t key_size,
* or for all other general purposes
*/
size_t ecryptfs_get_key_size_to_enc_data(
struct ecryptfs_crypt_stat *crypt_stat)
const struct ecryptfs_crypt_stat *crypt_stat)
{
if (!crypt_stat)
return 0;
@ -299,7 +317,7 @@ size_t ecryptfs_get_key_size_to_enc_data(
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_key_size_to_store_key(
struct ecryptfs_crypt_stat *crypt_stat)
const struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = 0;
@ -329,14 +347,14 @@ size_t ecryptfs_get_key_size_to_store_key(
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
const char *cipher)
const struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = 0;
if (!cipher)
if (!crypt_stat)
return 0;
salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
salt_size = ecryptfs_get_salt_size_for_cipher(crypt_stat);
if (salt_size >= stored_key_size) {
ecryptfs_printk(KERN_WARNING,
@ -350,12 +368,26 @@ size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
}
/**
* Given cipher, the function returns appropriate salt size.
* Given crypt_stat, the function returns appropriate salt size.
*/
size_t ecryptfs_get_salt_size_for_cipher(const char *cipher)
size_t ecryptfs_get_salt_size_for_cipher(
const struct ecryptfs_crypt_stat *crypt_stat)
{
if (!get_events() || !(get_events()->get_salt_key_size_cb))
return 0;
return get_events()->get_salt_key_size_cb(cipher);
return get_events()->get_salt_key_size_cb(crypt_stat);
}
/**
* Given mount_crypt_stat, the function returns appropriate salt size.
*/
size_t ecryptfs_get_salt_size_for_cipher_mount(
const struct ecryptfs_mount_crypt_stat *crypt_stat)
{
if (!get_events() || !(get_events()->get_salt_key_size_cb))
return 0;
return get_events()->get_salt_key_size_cb(crypt_stat);
}

View file

@ -1202,7 +1202,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
auth_tok->session_key.decrypted_key_size);
crypt_stat->key_size = ecryptfs_get_key_size_to_restore_key(
auth_tok->session_key.decrypted_key_size, full_cipher);
auth_tok->session_key.decrypted_key_size, crypt_stat);
ecryptfs_parse_full_cipher(full_cipher,
crypt_stat->cipher, crypt_stat->cipher_mode);
@ -1214,7 +1214,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->key_size);
ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
full_cipher);
crypt_stat);
}
out:
kfree(msg);
@ -1487,7 +1487,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
crypt_stat->key_size =
ecryptfs_get_key_size_to_restore_key(
(*new_auth_tok)->session_key.encrypted_key_size,
full_cipher);
crypt_stat);
}
rc = ecryptfs_init_crypt_ctx(crypt_stat);
@ -1687,8 +1687,6 @@ static int
decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_crypt_stat *crypt_stat)
{
unsigned char final[2*ECRYPTFS_MAX_CIPHER_NAME_SIZE+1];
struct scatterlist dst_sg[2];
struct scatterlist src_sg[2];
struct mutex *tfm_mutex;
@ -1762,9 +1760,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode,
final, sizeof(final)));
crypt_stat);
}
out:
return rc;
@ -2332,10 +2328,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
crypt_stat->key_size);
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the salt key\n",
ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode,
final, sizeof(final))));
ecryptfs_get_salt_size_for_cipher(crypt_stat));
rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
(*key_rec).enc_key_size);
mutex_unlock(tfm_mutex);

View file

@ -292,7 +292,6 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
int cipher_key_bytes_set = 0;
int fn_cipher_key_bytes;
int fn_cipher_key_bytes_set = 0;
size_t salt_size = 0;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&sbi->mount_crypt_stat;
substring_t args[MAX_OPT_ARGS];
@ -447,22 +446,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
strcpy(mount_crypt_stat->global_default_fn_cipher_name,
mount_crypt_stat->global_default_cipher_name);
if (cipher_key_bytes_set) {
salt_size = ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(
mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_mode,
final, sizeof(final)));
if (!ecryptfs_check_space_for_salt(
mount_crypt_stat->global_default_cipher_key_size,
salt_size)) {
ecryptfs_printk(
KERN_WARNING,
"eCryptfs internal error: no space for salt");
}
} else
if (!cipher_key_bytes_set)
mount_crypt_stat->global_default_cipher_key_size = 0;
if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)

View file

@ -119,7 +119,7 @@ struct ecryptfs_auth_tok {
* such as ecryptfs_get_key_size(), ecryptfs_get_cipher() etc.
*/
struct ecryptfs_events {
bool (*is_cipher_supported_cb)(const char *cipher);
bool (*is_cipher_supported_cb)(const void *ecrytpfs_data);
void (*open_cb)(struct inode *inode, void *ecrytpfs_data);
void (*release_cb)(struct inode *inode);
int (*encrypt_cb)(struct page *in_page, struct page *out_page,
@ -127,26 +127,28 @@ struct ecryptfs_events {
int (*decrypt_cb)(struct page *in_page, struct page *out_page,
struct inode *inode, unsigned long extent_offset);
bool (*is_hw_crypt_cb)(void);
size_t (*get_salt_key_size_cb)(const char *cipher);
size_t (*get_salt_key_size_cb)(const void *ecrytpfs_data);
};
int ecryptfs_register_to_events(struct ecryptfs_events *ops);
int ecryptfs_register_to_events(const struct ecryptfs_events *ops);
int ecryptfs_unregister_from_events(int user_handle);
const unsigned char *ecryptfs_get_key(void *ecrytpfs_data);
const unsigned char *ecryptfs_get_key(const void *ecrytpfs_data);
size_t ecryptfs_get_key_size(void *ecrytpfs_data);
size_t ecryptfs_get_key_size(const void *ecrytpfs_data);
const unsigned char *ecryptfs_get_salt(void *ecrytpfs_data);
const unsigned char *ecryptfs_get_salt(const void *ecrytpfs_data);
size_t ecryptfs_get_salt_size(void *ecrytpfs_data);
size_t ecryptfs_get_salt_size(const void *ecrytpfs_data);
const unsigned char *ecryptfs_get_cipher(void *ecrytpfs_data);
bool ecryptfs_cipher_match(const void *ecrytpfs_data,
const unsigned char *cipher, size_t cipher_size);
bool ecryptfs_is_page_in_metadata(void *ecrytpfs_data, pgoff_t offset);
bool ecryptfs_is_page_in_metadata(const void *ecrytpfs_data, pgoff_t offset);
bool ecryptfs_is_data_equal(void *ecrytpfs_data1, void *ecrytpfs_data2);
bool ecryptfs_is_data_equal(const void *ecrytpfs_data1,
const void *ecrytpfs_data2);
#endif /* _LINUX_ECRYPTFS_H */

View file

@ -276,13 +276,13 @@ static int pfk_set_ecryptfs_data(struct inode *inode, void *ecryptfs_data)
/**
* pfk_parse_cipher() - translate string cipher to enum
* @cipher: cipher in string as received from ecryptfs
* pfk_parse_cipher() - parse cipher from ecryptfs to enum
* @ecryptfs_data: ecrypfs data
* @algo: pointer to store the output enum (can be null)
*
* return 0 in case of success, error otherwise (i.e not supported cipher)
*/
static int pfk_parse_cipher(const unsigned char *cipher,
static int pfk_parse_cipher(const void *ecryptfs_data,
enum ice_cryto_algo_mode *algo)
{
/*
@ -291,11 +291,12 @@ static int pfk_parse_cipher(const unsigned char *cipher,
* be introduced
*/
if (!cipher)
return -EPERM;
if (!ecryptfs_data)
return -EINVAL;
if (!strcmp(cipher, PFK_SUPPORTED_CIPHER) == 0) {
pr_debug("not supported alghoritm %s\n", cipher);
if (!ecryptfs_cipher_match(ecryptfs_data,
PFK_SUPPORTED_CIPHER, sizeof(PFK_SUPPORTED_CIPHER))) {
pr_debug("ecryptfs alghoritm is not supported by pfk\n");
return -EINVAL;
}
@ -427,13 +428,6 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
goto end;
}
cipher = ecryptfs_get_cipher(ecryptfs_data);
if (!cipher) {
pr_err("could not parse key from ecryptfs\n");
ret = -EINVAL;
goto end;
}
ret = pfk_parse_cipher(cipher, &algo_mode);
if (ret != 0) {
pr_debug("not supported cipher\n");
@ -587,7 +581,6 @@ end:
static void pfk_open_cb(struct inode *inode, void *ecryptfs_data)
{
size_t key_size;
const unsigned char *cipher = NULL;
if (!pfk_is_ready())
return;
@ -603,13 +596,7 @@ static void pfk_open_cb(struct inode *inode, void *ecryptfs_data)
return;
}
cipher = ecryptfs_get_cipher(ecryptfs_data);
if (!cipher) {
pr_err("could not parse key from ecryptfs\n");
return;
}
if (0 != pfk_parse_cipher(cipher, NULL)) {
if (0 != pfk_parse_cipher(ecryptfs_data, NULL)) {
pr_debug("open_cb: not supported cipher\n");
return;
}
@ -677,20 +664,21 @@ static void pfk_release_cb(struct inode *inode)
pfk_kc_remove_key_with_salt(key, key_size, salt, salt_size);
mutex_lock(&pfk_lock);
pfk_set_ecryptfs_data(inode, NULL);
mutex_unlock(&pfk_lock);
}
static bool pfk_is_cipher_supported_cb(const char *cipher)
static bool pfk_is_cipher_supported_cb(const void *ecryptfs_data)
{
if (!pfk_is_ready())
return false;
if (!cipher)
if (!ecryptfs_data)
return false;
return (pfk_parse_cipher(cipher, NULL)) == 0;
return (pfk_parse_cipher(ecryptfs_data, NULL)) == 0;
}
static bool pfk_is_hw_crypt_cb(void)
@ -701,12 +689,12 @@ static bool pfk_is_hw_crypt_cb(void)
return true;
}
static size_t pfk_get_salt_key_size_cb(const char *cipher)
static size_t pfk_get_salt_key_size_cb(const void *ecryptfs_data)
{
if (!pfk_is_ready())
return 0;
if (!pfk_is_cipher_supported_cb(cipher))
if (!pfk_is_cipher_supported_cb(ecryptfs_data))
return 0;
return PFK_SUPPORTED_SALT_SIZE;