Re: [PATCH] eCryptfs: ensure copy to crypt_stat->cipher does not overrun

From: Tyler Hicks
Date: Mon Feb 23 2015 - 19:31:13 EST


On 2015-02-23 11:34:10, Colin King wrote:
> From: Colin Ian King <colin.king@xxxxxxxxxxxxx>
>
> The patch 237fead61998: "[PATCH] ecryptfs: fs/Makefile and
> fs/Kconfig" from Oct 4, 2006, leads to the following static checker
> warning:
>
> fs/ecryptfs/crypto.c:846 ecryptfs_new_file_context()
> error: off-by-one overflow 'crypt_stat->cipher' size 32. rl = '0-32'
>
> There is a mismatch between the size of ecryptfs_crypt_stat.cipher
> and ecryptfs_mount_crypt_stat.global_default_cipher_name causing the
> copy of the cipher name to cause a off-by-one string copy error. This
> fix ensures the space reserved for this string is the same size including
> the trailing zero at the end throughout ecryptfs.
>
> This fix avoids increasing the size of ecryptfs_crypt_stat.cipher
> and also ecryptfs_parse_tag_70_packet_silly_stack.cipher_string and instead
> reduces the of ECRYPTFS_MAX_CIPHER_NAME_SIZE to 31 and includes the + 1 for
> the end of string terminator.
>
> Signed-off-by: Colin Ian King <colin.king@xxxxxxxxxxxxx>

Thanks for the patch, Colin! It looks to me like it is the correct
change.

I've added Dan to cc and will add a Reported-by patch tag to give him
proper credit.

However, I don't think that this overflow can be triggered. The
ecryptfs_mount_crypt_stat.global_default_cipher_name buffer is filled
from the value of the 'ecryptfs_cipher' mount argument. That mount
argument value is validated by the ecryptfs_code_for_cipher_string()
function. It requires that the string matches one of the strings in this
array:

static struct ecryptfs_cipher_code_str_map_elem
ecryptfs_cipher_code_str_map[] = {
{"aes",RFC2440_CIPHER_AES_128 },
{"blowfish", RFC2440_CIPHER_BLOWFISH},
{"des3_ede", RFC2440_CIPHER_DES3_EDE},
{"cast5", RFC2440_CIPHER_CAST_5},
{"twofish", RFC2440_CIPHER_TWOFISH},
{"cast6", RFC2440_CIPHER_CAST_6},
{"aes", RFC2440_CIPHER_AES_192},
{"aes", RFC2440_CIPHER_AES_256}
};

None of those cipher strings are long enough to overflow the 32 byte
ecryptfs_crypt_stat.cipher or
ecryptfs_parse_tag_70_packet_silly_stack.cipher_string buffers.

This is a valid cleanup that will protect us from accidentally
overflowing the buffer in the future so I'm going to go ahead and apply
it to my next branch. I'll add a comment making it clear that this is
hardening/cleanup and there is no actual overflow.

Tyler

> ---
> fs/ecryptfs/ecryptfs_kernel.h | 4 ++--
> fs/ecryptfs/keystore.c | 2 +-
> fs/ecryptfs/main.c | 2 +-
> 3 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
> index 90d1882..5ba029e 100644
> --- a/fs/ecryptfs/ecryptfs_kernel.h
> +++ b/fs/ecryptfs/ecryptfs_kernel.h
> @@ -124,7 +124,7 @@ ecryptfs_get_key_payload_data(struct key *key)
> }
>
> #define ECRYPTFS_MAX_KEYSET_SIZE 1024
> -#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
> +#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 31
> #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
> #define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
> #define ECRYPTFS_SALT_BYTES 2
> @@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
> struct crypto_ablkcipher *tfm;
> struct crypto_hash *hash_tfm; /* Crypto context for generating
> * the initialization vectors */
> - unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
> + unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
> unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
> unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
> struct list_head keysig_list;
> diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
> index 917bd5c..6bd67e2 100644
> --- a/fs/ecryptfs/keystore.c
> +++ b/fs/ecryptfs/keystore.c
> @@ -891,7 +891,7 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
> struct blkcipher_desc desc;
> char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
> char iv[ECRYPTFS_MAX_IV_BYTES];
> - char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
> + char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
> };
>
> /**
> diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
> index d9eb84b..76dfb01 100644
> --- a/fs/ecryptfs/main.c
> +++ b/fs/ecryptfs/main.c
> @@ -407,7 +407,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
> if (!cipher_name_set) {
> int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
>
> - BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);
> + BUG_ON(cipher_name_len > ECRYPTFS_MAX_CIPHER_NAME_SIZE);
> strcpy(mount_crypt_stat->global_default_cipher_name,
> ECRYPTFS_DEFAULT_CIPHER);
> }
> --
> 2.1.4
>

Attachment: signature.asc
Description: Digital signature