From 2576f2458f10edb40a3fe5a74436d6382ef09cd5 Mon Sep 17 00:00:00 2001 From: mhalcrow@us.ibm.com Date: Thu, 3 Jan 2008 13:34:27 -0600 Subject: [PATCH] HMAC --- fs/ecryptfs/Makefile | 2 +- fs/ecryptfs/crypto.c | 190 +++++++++++++- fs/ecryptfs/ecryptfs_kernel.h | 64 +++++- fs/ecryptfs/file.c | 29 ++- fs/ecryptfs/hmac.c | 611 +++++++++++++++++++++++++++++++++++++++++ fs/ecryptfs/inode.c | 3 + fs/ecryptfs/keystore.c | 125 +++++++++- fs/ecryptfs/main.c | 13 +- 8 files changed, 1024 insertions(+), 13 deletions(-) create mode 100644 fs/ecryptfs/hmac.c diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile index 7688570..ba209e5 100644 --- a/fs/ecryptfs/Makefile +++ b/fs/ecryptfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o -ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o +ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o hmac.o diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f8ef0af..aad5bc6 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -80,6 +80,44 @@ void ecryptfs_from_hex(char *dst, char *src, int dst_size) } } +int ecryptfs_calculate_hmac(char * dst, struct ecryptfs_crypt_stat *crypt_stat, + struct scatterlist *sg, int len) +{ + struct hash_desc desc = { + .tfm = crypt_stat->hmac_tfm, + .flags = CRYPTO_TFM_REQ_MAY_SLEEP + }; + int rc = 0; + + mutex_lock(&crypt_stat->cs_hmac_tfm_mutex); + if (!desc.tfm) { + desc.tfm = crypto_alloc_hash(crypt_stat->hmac, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) { + rc = PTR_ERR(desc.tfm); + ecryptfs_printk(KERN_ERR, "Error attempting to " + "allocate crypto context; rc = [%d]\n", + rc); + goto out; + } + rc = crypto_hash_setkey(desc.tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error setting hmac key [%d]", + rc); + goto out; + } + crypt_stat->hmac_tfm = desc.tfm; + } + crypto_hash_init(&desc); + crypto_hash_update(&desc, sg, len); + crypto_hash_final(&desc, dst); + mutex_unlock(&crypt_stat->cs_hmac_tfm_mutex); +out: + return rc; +} + + /** * ecryptfs_calculate_md5 - calculates the md5 of @src * @dst: Pointer to 16 bytes of allocated memory @@ -251,6 +289,15 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) kmem_cache_free(ecryptfs_key_sig_cache, key_sig); } mutex_unlock(&crypt_stat->keysig_list_mutex); + + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + mutex_lock(&crypt_stat->cs_hmac_mutex); + if (crypt_stat->hmac_tfm) + crypto_free_hash(crypt_stat->hmac_tfm); + ecryptfs_free_hmac_table(crypt_stat->root); + mutex_unlock(&crypt_stat->cs_hmac_mutex); + } + memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); } @@ -379,9 +426,19 @@ out: void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, struct ecryptfs_crypt_stat *crypt_stat) { - (*offset) = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) - + (crypt_stat->extent_size * extent_num)); + size_t first_level_extents = 0; + size_t second_level_extents = 0; + loff_t lower_extent_num; + + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + second_level_extents = (extent_num / HMAC_PER_EXTENT) + 1; + first_level_extents = extent_num + / (HMAC_PER_EXTENT * HMAC_PER_EXTENT) + 1; + } + lower_extent_num = first_level_extents + second_level_extents + + extent_num; + (*offset) = crypt_stat->extent_size * lower_extent_num + + crypt_stat->num_header_bytes_at_front; } /** @@ -475,11 +532,15 @@ int ecryptfs_encrypt_page(struct page *page) char *enc_extent_virt = NULL; struct page *enc_extent_page; loff_t extent_offset; + loff_t num_extents_per_page; + loff_t base_extent; int rc = 0; ecryptfs_inode = page->mapping->host; crypt_stat = &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); + num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; + base_extent = page->index * num_extents_per_page; if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0, PAGE_CACHE_SIZE); @@ -514,6 +575,14 @@ int ecryptfs_encrypt_page(struct page *page) * (PAGE_CACHE_SIZE / crypt_stat->extent_size)) + extent_offset), crypt_stat); + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_update_hmac(crypt_stat, + ecryptfs_inode, page, + (extent_offset * crypt_stat->extent_size), + (base_extent + extent_offset)); + if (rc) + goto out; + } rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt, offset, crypt_stat->extent_size); if (rc) { @@ -608,12 +677,16 @@ int ecryptfs_decrypt_page(struct page *page) struct ecryptfs_crypt_stat *crypt_stat; char *enc_extent_virt = NULL; struct page *enc_extent_page; - unsigned long extent_offset; + loff_t extent_offset; + loff_t num_extents_per_page; + loff_t base_extent; int rc = 0; ecryptfs_inode = page->mapping->host; crypt_stat = &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); + num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; + base_extent = page->index * num_extents_per_page; if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment(page, page->index, 0, PAGE_CACHE_SIZE, @@ -657,6 +730,15 @@ int ecryptfs_decrypt_page(struct page *page) "rc = [%d]\n", __FUNCTION__, rc); goto out; } + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_verify_hmac(crypt_stat, ecryptfs_inode, + page, extent_offset * crypt_stat->extent_size, + base_extent + extent_offset); + if (rc) { + ecryptfs_printk(KERN_ERR, "INVALID HMAC\n"); + goto out; + } + } } out: kfree(enc_extent_virt); @@ -917,6 +999,8 @@ static void ecryptfs_copy_mount_wide_flags_to_inode_flags( crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED; + if (mount_crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) + crypt_stat->flags |= ECRYPTFS_ENABLE_HMAC; } static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs( @@ -962,6 +1046,9 @@ static void ecryptfs_set_default_crypt_stat_vals( crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); crypt_stat->file_version = ECRYPTFS_FILE_VERSION; crypt_stat->mount_crypt_stat = mount_crypt_stat; + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + ecryptfs_init_hmac(crypt_stat); + } } /** @@ -997,6 +1084,13 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) crypt_stat->flags |= (ECRYPTFS_ENCRYPTED | ECRYPTFS_KEY_VALID); ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, mount_crypt_stat); + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_init_hmac(crypt_stat); + } + if (rc) { + printk(KERN_ERR "Error initializing hmac.\n"); + goto out; + } rc = ecryptfs_copy_mount_wide_sigs_to_inode_sigs(crypt_stat, mount_crypt_stat); if (rc) { @@ -1135,6 +1229,66 @@ struct ecryptfs_cipher_code_str_map_elem { * cipher_code is whatever OpenPGP applicatoins use to identify the * ciphers. List in order of probability. */ static struct ecryptfs_cipher_code_str_map_elem +ecryptfs_hmac_code_str_map[] = { + {"hmac(sha256)",RFC2440_DIGEST_SHA256 }, + {"hmac(md5)",RFC2440_DIGEST_MD5 }, + {"hmac(sha1)",RFC2440_DIGEST_SHA1 }, + {"hmac(sha384)",RFC2440_DIGEST_SHA384 }, + {"hmac(sha512)",RFC2440_DIGEST_SHA512 }, +}; + +/** + * ecryptfs_code_for_hmac_string + * @crypt_stat: The cryptographic context + * + * Returns zero on no match, or the cipher code on match + */ +u8 ecryptfs_code_for_hmac_string(struct ecryptfs_crypt_stat *crypt_stat) +{ + int i; + u8 code = 0; + struct ecryptfs_cipher_code_str_map_elem *map = + ecryptfs_hmac_code_str_map; + + for (i = 0; i < ARRAY_SIZE(ecryptfs_hmac_code_str_map); i++) { + if (strcmp(crypt_stat->hmac, map[i].cipher_str) == 0) { + code = map[i].cipher_code; + break; + } + } + return code; +} + +/** + * ecryptfs_cipher_code_to_string + * @str: Destination to write out the cipher name + * @cipher_code: The code to convert to cipher name string + * + * Returns zero on success + */ +int ecryptfs_hmac_code_to_string(char *str, u16 cipher_code) +{ + int rc = 0; + int i; + + str[0] = '\0'; + for (i = 0; i < ARRAY_SIZE(ecryptfs_hmac_code_str_map); i++) { + if (cipher_code == ecryptfs_hmac_code_str_map[i].cipher_code) { + strcpy(str, ecryptfs_hmac_code_str_map[i].cipher_str); + } + } + if (str[0] == '\0') { + ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: " + "[%d]\n", cipher_code); + rc = -EINVAL; + } + return rc; +} + +/* Add support for additional ciphers by adding elements here. The + * cipher_code is whatever OpenPGP applicatoins use to identify the + * ciphers. List in order of probability. */ +static struct ecryptfs_cipher_code_str_map_elem ecryptfs_cipher_code_str_map[] = { {"aes",RFC2440_CIPHER_AES_128 }, {"blowfish", RFC2440_CIPHER_BLOWFISH}, @@ -1301,8 +1455,18 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, if (rc) ecryptfs_printk(KERN_WARNING, "Error generating key packet " "set; rc = [%d]\n", rc); - if (size) { + offset += written; + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_write_tag_17_packet( page_virt, + PAGE_CACHE_SIZE - offset, + offset, crypt_stat, + &written); + if (rc) + ecryptfs_printk(KERN_WARNING, "Error writing hmac " + "packet, rc = [%d]\n", rc); offset += written; + } + if (size) { *size = offset; } return rc; @@ -1527,7 +1691,14 @@ static int ecryptfs_read_headers_virt(char *page_virt, } else set_default_header_data(crypt_stat); rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset), - ecryptfs_dentry); + ecryptfs_dentry, &bytes_read); + offset += bytes_read; + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_parse_tag_17_packet(page_virt, offset, + crypt_stat, &bytes_read, + PAGE_CACHE_SIZE - offset); + offset += bytes_read; + } out: return rc; } @@ -1604,6 +1775,13 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, mount_crypt_stat); + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_init_hmac(crypt_stat); + } + if (rc) { + printk(KERN_ERR "Error initializing hmac.\n"); + goto out; + } /* Read the first page from the underlying file */ page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER); if (!page_virt) { diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index ce7a5d4..7762abc 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -49,11 +49,13 @@ #define ECRYPTFS_VERSIONING_POLICY 0x00000008 #define ECRYPTFS_VERSIONING_XATTR 0x00000010 #define ECRYPTFS_VERSIONING_MULTKEY 0x00000020 +#define ECRYPTFS_VERSIONING_HMAC 0x00000040 #define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \ | ECRYPTFS_VERSIONING_PUBKEY \ | ECRYPTFS_VERSIONING_XATTR \ - | ECRYPTFS_VERSIONING_MULTKEY) + | ECRYPTFS_VERSIONING_MULTKEY\ + | ECRYPTFS_VERSIONING_HMAC) #define ECRYPTFS_MAX_PASSWORD_LENGTH 64 #define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH #define ECRYPTFS_SALT_SIZE 8 @@ -97,6 +99,15 @@ #define RFC2440_CIPHER_RSA 0x01 +#define RFC2440_DIGEST_MD5 0x01 +#define RFC2440_DIGEST_SHA1 0x02 +#define RFC2440_DIGEST_RMD160 0x03 +/* 4, 5, 6, and 7 are reserved */ +#define RFC2440_DIGEST_SHA256 0x08 +#define RFC2440_DIGEST_SHA384 0x09 +#define RFC2440_DIGEST_SHA512 0x0a + + /** * For convenience, we may need to pass around the encrypted session * key between kernel and userspace because the authentication token @@ -195,6 +206,7 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_SUPER_MAGIC 0xf15f #define ECRYPTFS_MAX_KEYSET_SIZE 1024 #define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32 +#define ECRYPTFS_MAX_HMAC_NAME_SIZE 32 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64 #define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */ #define ECRYPTFS_SALT_BYTES 2 @@ -203,16 +215,22 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64)) #define ECRYPTFS_DEFAULT_CIPHER "aes" #define ECRYPTFS_DEFAULT_KEY_BYTES 16 +#define ECRYPTFS_DEFAULT_HMAC "hmac(sha256)" +#define ECRYPTFS_HMAC_BYTES 32 #define ECRYPTFS_DEFAULT_HASH "md5" #define ECRYPTFS_TAG_1_PACKET_TYPE 0x01 #define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C #define ECRYPTFS_TAG_11_PACKET_TYPE 0xED +#define ECRYPTFS_TAG_17_PACKET_TYPE 0x11 +#define ECRYPTFS_TAG_20_PACKET_TYPE 0x14 #define ECRYPTFS_TAG_64_PACKET_TYPE 0x40 #define ECRYPTFS_TAG_65_PACKET_TYPE 0x41 #define ECRYPTFS_TAG_66_PACKET_TYPE 0x42 #define ECRYPTFS_TAG_67_PACKET_TYPE 0x43 #define MD5_DIGEST_SIZE 16 +#define HMAC_PER_EXTENT (ECRYPTFS_DEFAULT_EXTENT_SIZE / ECRYPTFS_HMAC_BYTES) + struct ecryptfs_key_sig { struct list_head crypt_stat_list; char keysig[ECRYPTFS_SIG_SIZE_HEX]; @@ -234,6 +252,7 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_KEY_VALID 0x00000080 #define ECRYPTFS_METADATA_IN_XATTR 0x00000100 #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200 +#define ECRYPTFS_ROOT_HMAC 0x00000800 u32 flags; unsigned int file_version; size_t iv_bytes; @@ -241,21 +260,36 @@ struct ecryptfs_crypt_stat { size_t extent_size; /* Data extent size; default is 4096 */ size_t key_size; size_t extent_shift; + size_t root_hmac_header_offset; + size_t hmac_bytes; unsigned int extent_mask; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct crypto_blkcipher *tfm; struct crypto_hash *hash_tfm; /* Crypto context for generating * the initialization vectors */ + struct crypto_hash *hmac_tfm; + struct ecryptfs_hmac_table *root; unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; + unsigned char hmac[ECRYPTFS_MAX_HMAC_NAME_SIZE]; unsigned char key[ECRYPTFS_MAX_KEY_BYTES]; unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES]; struct list_head keysig_list; struct mutex keysig_list_mutex; struct mutex cs_tfm_mutex; struct mutex cs_hash_tfm_mutex; + struct mutex cs_hmac_tfm_mutex; + struct mutex cs_hmac_mutex; struct mutex cs_mutex; }; +struct ecryptfs_hmac_table { +#define ECRYPTFS_HMAC_EXTENT_DIRTY 0x00000001 + unsigned char *extent; + size_t lwr_extent; + size_t flags; + struct ecryptfs_hmac_table *children[HMAC_PER_EXTENT]; +}; + /* inode private data. */ struct ecryptfs_inode_info { struct inode vfs_inode; @@ -527,6 +561,7 @@ extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_lower_page_cache; extern struct kmem_cache *ecryptfs_key_record_cache; +extern struct kmem_cache *ecryptfs_extent_cache; extern struct kmem_cache *ecryptfs_key_sig_cache; extern struct kmem_cache *ecryptfs_global_auth_tok_cache; extern struct kmem_cache *ecryptfs_key_tfm_cache; @@ -562,6 +597,8 @@ int ecryptfs_read_and_validate_header_region(char *data, struct inode *ecryptfs_inode); int ecryptfs_read_and_validate_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); +u8 ecryptfs_code_for_hmac_string(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_hmac_code_to_string(char *str, u16 cipher_code); u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code); void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); @@ -571,7 +608,15 @@ int ecryptfs_generate_key_packet_set(char *dest_base, size_t *len, size_t max); int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, - unsigned char *src, struct dentry *ecryptfs_dentry); + unsigned char *src, struct dentry *ecryptfs_dentry, + size_t *bytes_read); +int ecryptfs_write_tag_17_packet(char *dest, size_t remaining_bytes, + size_t offset, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *packet_size); +int ecryptfs_parse_tag_17_packet(char *data, size_t offset, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *packet_size, size_t max_packet_size); int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); int ecryptfs_inode_set(struct inode *inode, void *lower_inode); @@ -631,6 +676,21 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, char *sig); int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); +int ecryptfs_init_hmac(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_verify_root_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode); +int ecryptfs_calculate_hmac(char *dst, struct ecryptfs_crypt_stat *crypt_stat, + struct scatterlist *sg, int len); +void ecryptfs_truncate_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode); +int ecryptfs_hmac_close(struct inode *ecryptfs_inode); +int ecryptfs_update_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode, struct page *page, + int page_offset, int extent); +int ecryptfs_verify_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode, struct page *page, + int page_offset, int extent); +void ecryptfs_free_hmac_table(struct ecryptfs_hmac_table *root); void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c98c469..97ab164 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -222,6 +222,21 @@ static int ecryptfs_open(struct inode *inode, struct file *file) goto out; } } + /* + * TODO: How should HMAC be handled with passthrough? + * Currently HMAC is not included in passthrough, but it might + * be a nice feature in the future. + */ + if(crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_verify_root_hmac(crypt_stat, inode); + if (rc) { + rc = -EIO; + printk(KERN_WARNING "Unable to initialize " + "hmac data structure; returning -EIO\n"); + mutex_unlock(&crypt_stat->cs_mutex); + goto out_free; + } + } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, @@ -247,9 +262,21 @@ static int ecryptfs_flush(struct file *file, fl_owner_t td) static int ecryptfs_release(struct inode *inode, struct file *file) { + struct ecryptfs_crypt_stat *crypt_stat; + int rc = 0; + + crypt_stat = (&ecryptfs_inode_to_private(inode)->crypt_stat); + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + rc = ecryptfs_hmac_close(inode); + if (rc) { + printk(KERN_ERR "Error writing hmac extents to file\n"); + goto out; + } + } kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); - return 0; +out: + return rc; } static int diff --git a/fs/ecryptfs/hmac.c b/fs/ecryptfs/hmac.c new file mode 100644 index 0000000..671d7c3 --- /dev/null +++ b/fs/ecryptfs/hmac.c @@ -0,0 +1,611 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 2007 Trevor Highland + * Author(s): Trevor S. Highland + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ecryptfs_kernel.h" + +struct kmem_cache *ecryptfs_extent_cache; + +#define HEADER_EXTENTS ( (crypt_stat->num_header_bytes_at_front) \ + / (crypt_stat->extent_size)) +#define FL_HMAC(extent) (((extent) & 0x1fc000) >> 14) +#define SL_HMAC(extent) (((extent) & 0x3f80) >> 7) +#define TL_HMAC(extent) ((extent) & 0x7f) +#define FL_OFFSET (HMAC_PER_EXTENT * (HMAC_PER_EXTENT + 1) + 1) +#define SL_OFFSET (HMAC_PER_EXTENT + 1) + +int ecryptfs_init_hmac(struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc = 0; + + mutex_init(&crypt_stat->cs_hmac_tfm_mutex); + mutex_init(&crypt_stat->cs_hmac_mutex); + crypt_stat->root = kzalloc(sizeof(struct ecryptfs_hmac_table), + GFP_KERNEL); + if (!(crypt_stat->root)) { + rc = -ENOMEM; + goto out; + } + crypt_stat->root->extent = + kmem_cache_zalloc(ecryptfs_extent_cache, GFP_KERNEL); + if (!(crypt_stat->root)) { + rc = -ENOMEM; + goto out; + } + crypt_stat->hmac_bytes = ECRYPTFS_HMAC_BYTES; + if (strlen(ECRYPTFS_DEFAULT_HMAC) <= ECRYPTFS_MAX_CIPHER_NAME_SIZE) { + strcpy(crypt_stat->hmac, ECRYPTFS_DEFAULT_HMAC); + } +out: + return rc; +} + + +static int ecryptfs_read_hmac_root(struct inode *ecryptfs_inode, + struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc; + char *extent; + + extent = kmalloc(crypt_stat->extent_size, GFP_KERNEL); + rc = ecryptfs_read_lower(extent, 0, crypt_stat->extent_size, + ecryptfs_inode); + if (rc) + goto out; + memcpy(crypt_stat->root->extent, + &extent[crypt_stat->root_hmac_header_offset], + 2 * crypt_stat->hmac_bytes); + + kfree(extent); + +out: + return rc; +} + +static int ecryptfs_write_hmac_root_to_header(struct inode *ecryptfs_inode, + struct ecryptfs_crypt_stat *crypt_stat) +{ + int rc; + loff_t offset = crypt_stat->root_hmac_header_offset; + struct ecryptfs_hmac_table *root; + + root = crypt_stat->root; + if (crypt_stat->flags & ECRYPTFS_ROOT_HMAC) + offset += crypt_stat->hmac_bytes; + rc = ecryptfs_write_lower(ecryptfs_inode, root->extent, offset, + crypt_stat->hmac_bytes); + crypt_stat->flags ^= ECRYPTFS_ROOT_HMAC; + return rc; +} + +/* + * For performance reasons, hmac extents reside in memory until the file is + * closed. This functions flushes each of the hmac extents to disk. + */ + +int ecryptfs_hmac_close(struct inode *ecryptfs_inode) +{ + int rc = 0; + size_t i; + size_t j; + loff_t offset; + struct ecryptfs_crypt_stat *crypt_stat; + struct ecryptfs_hmac_table *root; + + crypt_stat = (&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); + + mutex_lock(&crypt_stat->cs_hmac_mutex); + root = crypt_stat->root; + if(!root) { + rc = -EIO; + goto out; + } + for (i = 0; i < HMAC_PER_EXTENT; i++) { + if (!root->children[i]) + break; + if (!(root->children[i]->flags & ECRYPTFS_HMAC_EXTENT_DIRTY)) { + continue; + } + for (j = 0; j < HMAC_PER_EXTENT; j++) { + if (!root->children[i]->children[j]) + break; + if (!(root->children[i]->children[j]->flags + & ECRYPTFS_HMAC_EXTENT_DIRTY)) { + continue; + } + offset = root->children[i]->children[j]->lwr_extent + * crypt_stat->extent_size; + rc = ecryptfs_write_lower(ecryptfs_inode, + root->children[i]->children[j]->extent, + offset, crypt_stat->extent_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error, writing hmac " + "extent. returning EIO\n"); + rc = -EIO; + goto out; + } + } + offset = root->children[i]->lwr_extent + * crypt_stat->extent_size; + rc = ecryptfs_write_lower(ecryptfs_inode, + root->children[i]->extent, + offset, crypt_stat->extent_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error, writing hmac extent. " + "returning EIO\n"); + rc = -EIO; + goto out; + } + } +out: + mutex_unlock(&crypt_stat->cs_hmac_mutex); + return rc; +} + + +static int ecryptfs_calculate_root_hmac(struct ecryptfs_crypt_stat *crypt_stat, + char *dst) +{ + struct hash_desc desc = { + .tfm = crypt_stat->hmac_tfm, + .flags = CRYPTO_TFM_REQ_MAY_SLEEP, + }; + struct ecryptfs_hmac_table *root; + struct scatterlist sg; + size_t i; + int rc; + + mutex_lock(&crypt_stat->cs_hmac_tfm_mutex); + root = crypt_stat->root; + if(!root) { + rc = -EIO; + goto out; + } + if (!desc.tfm) { + desc.tfm = crypto_alloc_hash(crypt_stat->hmac, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) { + rc = PTR_ERR(desc.tfm); + ecryptfs_printk(KERN_ERR, "Error attempting to " + "allocate crypto context; rc = [%d]\n", + rc); + goto out; + } + rc = crypto_hash_setkey(desc.tfm, crypt_stat->key, + crypt_stat->key_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error setting hmac key [%d]", + rc); + goto out; + } + crypt_stat->hmac_tfm = desc.tfm; + } + + crypto_hash_init(&desc); + for (i=0; i < HMAC_PER_EXTENT; i++) { + if (!root->children[i]) + break; + sg_init_one(&sg, root->children[i]->extent, + crypt_stat->extent_size); + crypto_hash_update(&desc, &sg, crypt_stat->extent_size); + } + crypto_hash_final(&desc, dst); +out: + mutex_unlock(&crypt_stat->cs_hmac_tfm_mutex); + return rc; +} + +static int ecryptfs_init_hmac_node(struct ecryptfs_hmac_table **hmac_node, + size_t lwr_extent) +{ + int rc = 0; + *hmac_node = kzalloc(sizeof(struct ecryptfs_hmac_table),GFP_KERNEL); + if (!(*hmac_node)) { + rc = -ENOMEM; + goto out; + } + (*hmac_node)->lwr_extent = lwr_extent; + (*hmac_node)->extent = + kmem_cache_zalloc(ecryptfs_extent_cache, GFP_KERNEL); + if (!((*hmac_node)->extent)) { + rc = -ENOMEM; + goto out; + } +out: + return rc; +} + +int ecryptfs_verify_root_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode) +{ + int rc = 0; + size_t i; + size_t lwr_extent; + u64 file_size; + struct ecryptfs_hmac_table *root; + char *root_hmac; + + + root_hmac = kzalloc(ECRYPTFS_HMAC_BYTES, GFP_KERNEL); + if (!root_hmac) { + ecryptfs_printk(KERN_ERR, "Error allocating root_hmac\n"); + return -ENOMEM; + } + + mutex_lock(&crypt_stat->cs_hmac_mutex); + root = crypt_stat->root; + if (!root) { + rc = -EIO; + goto out; + } + ecryptfs_read_hmac_root(ecryptfs_inode, crypt_stat); + + /* + * Allocate first level HMAC nodes that have not been + * prviously initialized + */ + file_size = (u64)i_size_read(ecryptfs_inode); + for (i=0; ichildren[i]) + continue; + if (file_size <= crypt_stat->extent_size * HMAC_PER_EXTENT + * HMAC_PER_EXTENT * i) + break; + lwr_extent = HEADER_EXTENTS + (i * FL_OFFSET); + rc = ecryptfs_init_hmac_node(&(root->children[i]), lwr_extent); + if (rc) + goto out; + rc = ecryptfs_read_lower(root->children[i]->extent, + lwr_extent * crypt_stat->extent_size, + crypt_stat->extent_size, + ecryptfs_inode); + if (rc) + goto out; + } + ecryptfs_calculate_root_hmac(crypt_stat, root_hmac); + if (!memcmp(root_hmac, crypt_stat->root->extent, ECRYPTFS_HMAC_BYTES)) { + crypt_stat->flags |= ECRYPTFS_ROOT_HMAC; + goto out; + } + if (!memcmp(root_hmac, crypt_stat->root->extent + ECRYPTFS_HMAC_BYTES, + ECRYPTFS_HMAC_BYTES)) { + crypt_stat->flags &= ~ECRYPTFS_ROOT_HMAC; + goto out; + } + ecryptfs_printk(KERN_ERR, "HMAC incorrect; return -EIO \n"); + rc = -EIO; +out: + mutex_unlock(&crypt_stat->cs_hmac_mutex); + kfree(root_hmac); + return rc; +} + +static int load_hmac_extents(struct ecryptfs_crypt_stat *crypt_stat, int extent, + struct inode *ecryptfs_inode) +{ + int rc = 0; + size_t lwr_extent; + u64 file_size; + char *hmac_addr; + char *hmac_value; + struct scatterlist sg; + struct ecryptfs_hmac_table *level1_node; + struct ecryptfs_hmac_table *level2_node; + struct ecryptfs_hmac_table *root; + + hmac_value = kmalloc(ECRYPTFS_HMAC_BYTES, GFP_KERNEL); + if (!hmac_value) { + ecryptfs_printk(KERN_ERR, "Error allocating hmac_value\n"); + return -ENOMEM; + } + + root = crypt_stat->root; + if (!root) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + goto out; + } + /* + * Allocate first level HMAC node if it has not been + * prviously initialized + */ + if (!(root->children[FL_HMAC(extent)])) { + lwr_extent = HEADER_EXTENTS + (FL_HMAC(extent) * FL_OFFSET); + rc = ecryptfs_init_hmac_node(&(root->children[FL_HMAC(extent)]), + lwr_extent); + if (rc) + goto out; + level1_node = root->children[FL_HMAC(extent)]; + } else { + level1_node = root->children[FL_HMAC(extent)]; + } + + /* + * Allocate sencond level HMAC node if it has not been + * previously initialized + */ + if (!(level1_node->children[SL_HMAC(extent)])) { + lwr_extent = (level1_node->lwr_extent + 1) + + (SL_HMAC(extent) * SL_OFFSET); + rc = ecryptfs_init_hmac_node( + &(level1_node->children[SL_HMAC(extent)]), + lwr_extent); + if (rc) + goto out; + level2_node = level1_node->children[SL_HMAC(extent)]; + file_size = (u64)i_size_read(ecryptfs_inode); + if (file_size <= crypt_stat->extent_size * (extent & ~0x7f)) { + goto out; + } + rc = ecryptfs_read_lower(level2_node->extent, + lwr_extent * crypt_stat->extent_size, + crypt_stat->extent_size, + ecryptfs_inode); + if (rc) + goto out; + sg_init_one(&sg, level2_node->extent, crypt_stat->extent_size); + rc = ecryptfs_calculate_hmac(hmac_value, crypt_stat, &sg, + crypt_stat->extent_size); + if (rc) + goto out; + hmac_addr = level1_node->extent + + (SL_HMAC(extent) * ECRYPTFS_HMAC_BYTES); + if (memcmp(hmac_value, hmac_addr, ECRYPTFS_HMAC_BYTES)) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + goto out; + } + } +out: + kfree(hmac_value); + return rc; +} + +int ecryptfs_update_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode, struct page *page, + int page_offset, int extent) +{ + int rc; + struct ecryptfs_hmac_table *level1_node; + struct ecryptfs_hmac_table *level2_node; + struct scatterlist sg; + char *hmac_addr; + + + mutex_lock(&crypt_stat->cs_hmac_mutex); + if (!crypt_stat->root) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + goto out; + } + rc = load_hmac_extents(crypt_stat, extent, ecryptfs_inode); + if (rc) + goto out; + if (!(crypt_stat->root->children[FL_HMAC(extent)])) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + goto out; + } + level1_node = crypt_stat->root->children[FL_HMAC(extent)]; + + if (!(level1_node->children[SL_HMAC(extent)])) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + } + level2_node = level1_node->children[SL_HMAC(extent)]; + + /* + * Update the Second level HMAC + */ + hmac_addr = level2_node->extent + + (TL_HMAC(extent) * ECRYPTFS_HMAC_BYTES); + sg_init_table(&sg, 1); + sg_set_page(&sg, page, crypt_stat->extent_size, page_offset); + rc = ecryptfs_calculate_hmac(hmac_addr, crypt_stat, &sg, + crypt_stat->extent_size); + level2_node->flags |= ECRYPTFS_HMAC_EXTENT_DIRTY; + + /* + * Update the first level HMAC + */ + hmac_addr = level1_node->extent + + (SL_HMAC(extent) * ECRYPTFS_HMAC_BYTES); + sg_init_one(&sg, level2_node->extent, crypt_stat->extent_size); + rc = ecryptfs_calculate_hmac(hmac_addr, crypt_stat, &sg, + crypt_stat->extent_size); + if (rc) + goto out; + level1_node->flags |= ECRYPTFS_HMAC_EXTENT_DIRTY; + ecryptfs_calculate_root_hmac(crypt_stat, crypt_stat->root->extent); + ecryptfs_write_hmac_root_to_header(ecryptfs_inode, crypt_stat); +out: + mutex_unlock(&crypt_stat->cs_hmac_mutex); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + rc = -EIO; + } + return rc; +} + +int ecryptfs_verify_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode, struct page *page, + int page_offset, int extent) +{ + int rc; + struct ecryptfs_hmac_table *root; + struct ecryptfs_hmac_table *node; + struct scatterlist sg; + char *hmac_value; + char *hmac_addr; + + hmac_value = kmalloc(ECRYPTFS_HMAC_BYTES, GFP_KERNEL); + if (!hmac_value) { + ecryptfs_printk(KERN_ERR, "Error allocating hmac_value\n"); + return -ENOMEM; + } + + mutex_lock(&crypt_stat->cs_hmac_mutex); + root = crypt_stat->root; + if (!root) { + rc = -EIO; + goto out; + } + rc = load_hmac_extents(crypt_stat, extent, ecryptfs_inode); + if (rc) { + goto out; + } + if (!(crypt_stat->root->children[FL_HMAC(extent)])) { + rc = -EINVAL; + goto out; + } + + if (!(root->children[FL_HMAC(extent)]->children[SL_HMAC(extent)])) { + rc = -EINVAL; + goto out; + } + node = root->children[FL_HMAC(extent)]->children[SL_HMAC(extent)]; + + sg_init_table(&sg, 1); + sg_set_page(&sg, page, crypt_stat->extent_size, page_offset); + rc = ecryptfs_calculate_hmac(hmac_value, crypt_stat, &sg, + crypt_stat->extent_size); + if (rc) + goto out; + hmac_addr = node->extent + (TL_HMAC(extent) * ECRYPTFS_HMAC_BYTES); + if (memcmp(hmac_value, hmac_addr, ECRYPTFS_HMAC_BYTES)) { + rc = -EINVAL; + goto out; + } +out: + mutex_unlock(&crypt_stat->cs_hmac_mutex); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error returning EIO\n"); + return -EIO; + } + return rc; +} + +void ecryptfs_truncate_hmac(struct ecryptfs_crypt_stat *crypt_stat, + struct inode *ecryptfs_inode) +{ + struct ecryptfs_hmac_table *root; + struct ecryptfs_hmac_table *first_level_node; + size_t size; + size_t num_extents; + size_t i; + size_t j; + + size = i_size_read(ecryptfs_inode); + num_extents = size / crypt_stat->extent_size; + i = FL_HMAC((num_extents + 1)); + j = SL_HMAC((num_extents + 1)); + mutex_lock(&crypt_stat->cs_hmac_mutex); + root = crypt_stat->root; + if (!root) { + goto out; + } + if (j != 0) { + first_level_node = root->children[i]; + if (!first_level_node) { + goto out; + } + for (; j < HMAC_PER_EXTENT; j++) { + if (!first_level_node->children[j]) + goto out; + kmem_cache_free(ecryptfs_extent_cache, + first_level_node->children[j]->extent); + kfree(first_level_node->children[j]); + memset(&(first_level_node->children[j]), 0, + sizeof(struct ecryptfs_hmac_table *)); + } + i++; + } + for (; i < HMAC_PER_EXTENT; i++) { + first_level_node = root->children[i]; + if (!first_level_node) + goto out; + for (j = 0; j < HMAC_PER_EXTENT; j++) { + if (!first_level_node->children[j]) + goto out; + kmem_cache_free(ecryptfs_extent_cache, + first_level_node->children[j]->extent); + kfree(first_level_node->children[j]); + memset(&(first_level_node->children[j]), 0, + sizeof(struct ecryptfs_hmac_table *)); + } + kmem_cache_free(ecryptfs_extent_cache, + first_level_node->extent); + kfree(first_level_node); + memset(&(root->children[i]), 0, + sizeof(struct ecryptfs_hmac_table *)); + } + ecryptfs_calculate_root_hmac(crypt_stat, crypt_stat->root->extent); + ecryptfs_write_hmac_root_to_header(ecryptfs_inode, crypt_stat); +out: + mutex_unlock(&crypt_stat->cs_hmac_mutex); +} + + +/** + * ecryptfs_free_hmac_table + * @crypt_stat: Pointer to crypt_stat struct hmac table for the current inode + * + * Free all hmac extents and nodes for the hmac table + * + * This function should always succeed + */ +void ecryptfs_free_hmac_table(struct ecryptfs_hmac_table *root) +{ + struct ecryptfs_hmac_table *first_level_node; + size_t i = 0; + size_t j; + + if(!root) + return; + for (i = 0; i < HMAC_PER_EXTENT; i++) { + first_level_node = root->children[i]; + if (!first_level_node) + continue; + for (j = 0; j < HMAC_PER_EXTENT; j++) { + if (!first_level_node->children[j]) + continue; + kmem_cache_free(ecryptfs_extent_cache, + first_level_node->children[j]->extent); + kfree(first_level_node->children[j]); + } + kmem_cache_free(ecryptfs_extent_cache, + first_level_node->extent); + kfree(first_level_node); + } + if (root->extent) + kmem_cache_free(ecryptfs_extent_cache,root->extent); + kfree(root); +} diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 0b1ab01..0c50465 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -819,6 +819,9 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) vmtruncate(lower_dentry->d_inode, lower_size_after_truncate); } + if (crypt_stat->flags & ECRYPTFS_ENABLE_HMAC) { + ecryptfs_truncate_hmac(crypt_stat, inode); + } out_free: if (ecryptfs_file_to_private(&fake_ecryptfs_file)) kmem_cache_free(ecryptfs_file_info_cache, diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index f458c1f..4218e0f 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -134,6 +134,127 @@ static int write_packet_length(char *dest, size_t size, return rc; } +int +ecryptfs_write_tag_17_packet(char *dest, size_t remaining_bytes, size_t offset, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *packet_size) +{ + + /* + * ***** TAG 17 Packet Format ***** + * | Content Type | 1 byte | + * | Hash Identifier Length | 1 or 2 bytes | + * | Hash Identifier | arbitrary | + * | Root Hmac Length | 1 or 2 bytes | + * | Root Hmac | arbitrary | + */ + + int rc; + size_t packet_size_len; + size_t max_packet_size; + u8 hmac_code; + + max_packet_size = 1 /* Content Type*/ + + 2 /* Hash Identifier Length*/ + + ECRYPTFS_MAX_HMAC_NAME_SIZE /* Hash Identifier */ + + 2 /* Root Hmac Length */ + + 128; /* Root Hmac */ + if (max_packet_size > remaining_bytes) { + ecryptfs_printk(KERN_ERR, "Insufficient space remaining in " + "page to write tag 17 packet"); + rc = -EIO; + goto out; + } + *packet_size = offset; + dest[offset++] = ECRYPTFS_TAG_17_PACKET_TYPE; + hmac_code = ecryptfs_code_for_hmac_string(crypt_stat); + dest[offset++] = hmac_code; + rc = write_packet_length(&dest[offset], 2 * crypt_stat->hmac_bytes, + &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 17 packet " + "header, cannot generate packet length\n"); + goto out; + } + offset += packet_size_len; + crypt_stat->root_hmac_header_offset = offset; + offset += (2 * crypt_stat->hmac_bytes); + *packet_size = offset - *packet_size; +out: + return rc; +} + +int ecryptfs_parse_tag_17_packet(char *data, size_t offset, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *packet_size, size_t max_packet_size) +{ + + /* + * ***** TAG 17 Packet Format ***** + * | Content Type | 1 byte | + * | Hash Identifier Size | 1 or 2 bytes | + * | Hash Identifier | arbitrary | + * | Root Hmac Length | 1 or 2 bytes | + * | Root Hmac | arbitrary | + */ + + int rc; + size_t size; + size_t packet_size_len; + size_t start_offset; + + start_offset = offset; + if ( (offset + 1) - start_offset > max_packet_size) { + ecryptfs_printk(KERN_ERR, "Error the packet size exceeds " + "the max packet size\n"); + rc = -EIO; + goto out; + } + if ( !(data[offset++] == ECRYPTFS_TAG_17_PACKET_TYPE ) ){ + ecryptfs_printk(KERN_ERR, "Error unexpected packet type in " + "header\n"); + rc = -EINVAL; + goto out; + } + if ( (offset + 2) - start_offset > max_packet_size) { + ecryptfs_printk(KERN_ERR, "Error the packet size exceeds " + "the max packet size\n"); + rc = -EIO; + goto out; + } + if ( (offset + 2) - start_offset > max_packet_size) { + ecryptfs_printk(KERN_ERR, "Error the packet size exceeds " + "the max packet size\n"); + rc = -EIO; + goto out; + } + ecryptfs_hmac_code_to_string(crypt_stat->hmac, (u16)data[offset++]); + if ( (offset + 2) - start_offset > max_packet_size) { + ecryptfs_printk(KERN_ERR, "Error the packet size exceeds " + "the max packet size\n"); + rc = -EIO; + goto out; + } + rc = parse_packet_length(&data[offset], &size, &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error parsing tag 17 packet " + "header, cannot read packet length\n"); + goto out; + } + offset += packet_size_len; + if ( (offset + size) - start_offset > max_packet_size) { + ecryptfs_printk(KERN_ERR, "Error the packet size exceeds " + "the max packet size\n"); + rc = -EIO; + goto out; + } + crypt_stat->hmac_bytes = size / 2; + crypt_stat->root_hmac_header_offset = offset; + *packet_size = offset - start_offset; +out: + return rc; +} + static int write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, char **packet, size_t *packet_len) @@ -1127,7 +1248,8 @@ out: */ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, unsigned char *src, - struct dentry *ecryptfs_dentry) + struct dentry *ecryptfs_dentry, + size_t *bytes_read) { size_t i = 0; size_t found_auth_tok; @@ -1319,6 +1441,7 @@ found_matching_auth_tok: out_wipe_list: wipe_auth_tok_list(&auth_tok_list); out: + *bytes_read = i; return rc; } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index e5580bc..8fb61c7 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -230,7 +230,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug, ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes, ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, - ecryptfs_opt_encrypted_view, ecryptfs_opt_err }; + ecryptfs_opt_encrypted_view, ecryptfs_opt_hmac, ecryptfs_opt_err,}; static match_table_t tokens = { {ecryptfs_opt_sig, "sig=%s"}, @@ -243,7 +243,8 @@ static match_table_t tokens = { {ecryptfs_opt_passthrough, "ecryptfs_passthrough"}, {ecryptfs_opt_xattr_metadata, "ecryptfs_xattr_metadata"}, {ecryptfs_opt_encrypted_view, "ecryptfs_encrypted_view"}, - {ecryptfs_opt_err, NULL} + {ecryptfs_opt_hmac, "ecryptfs_hmac"}, + {ecryptfs_opt_err, NULL}, }; static int ecryptfs_init_global_auth_toks( @@ -393,6 +394,9 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) mount_crypt_stat->flags |= ECRYPTFS_ENCRYPTED_VIEW_ENABLED; break; + case ecryptfs_opt_hmac: + mount_crypt_stat->flags |= ECRYPTFS_ENABLE_HMAC; + break; case ecryptfs_opt_err: default: ecryptfs_printk(KERN_WARNING, @@ -693,6 +697,11 @@ static struct ecryptfs_cache_info { .name = "ecryptfs_key_tfm_cache", .size = sizeof(struct ecryptfs_key_tfm), }, + { + .cache = &ecryptfs_extent_cache, + .name = "ecryptfs_extent_cache", + .size = ECRYPTFS_DEFAULT_EXTENT_SIZE, + }, }; static void ecryptfs_free_kmem_caches(void) -- 1.5.1.6