eCryptfs: fix Tag 3 parsing code

Fix up the Tag 3 parsing code to handle size limits and boundaries more
explicitly.

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Michael Halcrow 2007-10-16 01:27:56 -07:00 committed by Linus Torvalds
parent 132181796a
commit c59becfcee
1 changed files with 35 additions and 54 deletions

View File

@ -643,22 +643,30 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
(*packet_size) = 0; (*packet_size) = 0;
(*new_auth_tok) = NULL; (*new_auth_tok) = NULL;
/**
/* we check that: *This format is inspired by OpenPGP; see RFC 2440
* one byte for the Tag 3 ID flag * packet tag 3
* two bytes for the body size *
* do not exceed the maximum_packet_size * Tag 3 identifier (1 byte)
* Max Tag 3 packet size (max 3 bytes)
* Version (1 byte)
* Cipher code (1 byte)
* S2K specifier (1 byte)
* Hash identifier (1 byte)
* Salt (ECRYPTFS_SALT_SIZE)
* Hash iterations (1 byte)
* Encrypted key (arbitrary)
*
* (ECRYPTFS_SALT_SIZE + 7) minimum packet size
*/ */
if (unlikely((*packet_size) + 3 > max_packet_size)) { if (max_packet_size < (ECRYPTFS_SALT_SIZE + 7)) {
ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); printk(KERN_ERR "Max packet size too large\n");
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
/* check for Tag 3 identifyer - one byte */
if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) { if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n", printk(KERN_ERR "First byte != 0x%.2x; invalid packet\n",
ECRYPTFS_TAG_3_PACKET_TYPE); ECRYPTFS_TAG_3_PACKET_TYPE);
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
@ -667,56 +675,36 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
auth_tok_list_item = auth_tok_list_item =
kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL);
if (!auth_tok_list_item) { if (!auth_tok_list_item) {
ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); printk(KERN_ERR "Unable to allocate memory\n");
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
(*new_auth_tok) = &auth_tok_list_item->auth_tok; (*new_auth_tok) = &auth_tok_list_item->auth_tok;
if ((rc = parse_packet_length(&data[(*packet_size)], &body_size,
/* check for body size - one to two bytes */ &length_size))) {
rc = parse_packet_length(&data[(*packet_size)], &body_size, printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
&length_size); rc);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc);
goto out_free; goto out_free;
} }
if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) { if (unlikely(body_size < (ECRYPTFS_SALT_SIZE + 5))) {
ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", printk(KERN_WARNING "Invalid body size ([%d])\n", body_size);
body_size);
rc = -EINVAL; rc = -EINVAL;
goto out_free; goto out_free;
} }
(*packet_size) += length_size; (*packet_size) += length_size;
/* now we know the length of the remainting Tag 3 packet size:
* 5 fix bytes for: version string, cipher, S2K ID, hash algo,
* number of hash iterations
* ECRYPTFS_SALT_SIZE bytes for salt
* body_size bytes minus the stuff above is the encrypted key size
*/
if (unlikely((*packet_size) + body_size > max_packet_size)) { if (unlikely((*packet_size) + body_size > max_packet_size)) {
ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); printk(KERN_ERR "Packet size exceeds max\n");
rc = -EINVAL; rc = -EINVAL;
goto out_free; goto out_free;
} }
/* There are 5 characters of additional information in the
* packet */
(*new_auth_tok)->session_key.encrypted_key_size = (*new_auth_tok)->session_key.encrypted_key_size =
body_size - (0x05 + ECRYPTFS_SALT_SIZE); (body_size - (ECRYPTFS_SALT_SIZE + 5));
ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n",
(*new_auth_tok)->session_key.encrypted_key_size);
/* Version 4 (from RFC2440) - one byte */
if (unlikely(data[(*packet_size)++] != 0x04)) { if (unlikely(data[(*packet_size)++] != 0x04)) {
ecryptfs_printk(KERN_DEBUG, "Unknown version number " printk(KERN_WARNING "Unknown version number [%d]\n",
"[%d]\n", data[(*packet_size) - 1]); data[(*packet_size) - 1]);
rc = -EINVAL; rc = -EINVAL;
goto out_free; goto out_free;
} }
/* cipher - one byte */
ecryptfs_cipher_code_to_string(crypt_stat->cipher, ecryptfs_cipher_code_to_string(crypt_stat->cipher,
(u16)data[(*packet_size)]); (u16)data[(*packet_size)]);
/* A little extra work to differentiate among the AES key /* A little extra work to differentiate among the AES key
@ -730,33 +718,26 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
(*new_auth_tok)->session_key.encrypted_key_size; (*new_auth_tok)->session_key.encrypted_key_size;
} }
ecryptfs_init_crypt_ctx(crypt_stat); ecryptfs_init_crypt_ctx(crypt_stat);
/* S2K identifier 3 (from RFC2440) */
if (unlikely(data[(*packet_size)++] != 0x03)) { if (unlikely(data[(*packet_size)++] != 0x03)) {
ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently " printk(KERN_WARNING "Only S2K ID 3 is currently supported\n");
"supported\n");
rc = -ENOSYS; rc = -ENOSYS;
goto out_free; goto out_free;
} }
/* TODO: finish the hash mapping */ /* TODO: finish the hash mapping */
/* hash algorithm - one byte */
switch (data[(*packet_size)++]) { switch (data[(*packet_size)++]) {
case 0x01: /* See RFC2440 for these numbers and their mappings */ case 0x01: /* See RFC2440 for these numbers and their mappings */
/* Choose MD5 */ /* Choose MD5 */
/* salt - ECRYPTFS_SALT_SIZE bytes */
memcpy((*new_auth_tok)->token.password.salt, memcpy((*new_auth_tok)->token.password.salt,
&data[(*packet_size)], ECRYPTFS_SALT_SIZE); &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
(*packet_size) += ECRYPTFS_SALT_SIZE; (*packet_size) += ECRYPTFS_SALT_SIZE;
/* This conversion was taken straight from RFC2440 */ /* This conversion was taken straight from RFC2440 */
/* number of hash iterations - one byte */
(*new_auth_tok)->token.password.hash_iterations = (*new_auth_tok)->token.password.hash_iterations =
((u32) 16 + (data[(*packet_size)] & 15)) ((u32) 16 + (data[(*packet_size)] & 15))
<< ((data[(*packet_size)] >> 4) + 6); << ((data[(*packet_size)] >> 4) + 6);
(*packet_size)++; (*packet_size)++;
/* Friendly reminder:
/* encrypted session key - * (*new_auth_tok)->session_key.encrypted_key_size =
* (body_size-5-ECRYPTFS_SALT_SIZE) bytes */ * (body_size - (ECRYPTFS_SALT_SIZE + 5)); */
memcpy((*new_auth_tok)->session_key.encrypted_key, memcpy((*new_auth_tok)->session_key.encrypted_key,
&data[(*packet_size)], &data[(*packet_size)],
(*new_auth_tok)->session_key.encrypted_key_size); (*new_auth_tok)->session_key.encrypted_key_size);
@ -766,7 +747,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
~ECRYPTFS_CONTAINS_DECRYPTED_KEY; ~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
(*new_auth_tok)->session_key.flags |= (*new_auth_tok)->session_key.flags |=
ECRYPTFS_CONTAINS_ENCRYPTED_KEY; ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
(*new_auth_tok)->token.password.hash_algo = 0x01; (*new_auth_tok)->token.password.hash_algo = 0x01; /* MD5 */
break; break;
default: default:
ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: " ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "