X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=fs%2Fecryptfs%2Fcrypto.c;h=6ac630625b70821274c4b8c753fbc90bc1daaec1;hb=e2bd99ec5c0e20ed6aeb079fa8f975c2dcd78a2c;hp=f63a7755fe8697ea7469182b1baa487fd1b48c7a;hpb=a17259a726c4c9806dc99bda5e904727de76b694;p=deliverable%2Flinux.git diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f63a7755fe86..6ac630625b70 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow * Michael C. Thompson * @@ -207,7 +207,7 @@ ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) mutex_init(&crypt_stat->cs_mutex); mutex_init(&crypt_stat->cs_tfm_mutex); mutex_init(&crypt_stat->cs_hash_tfm_mutex); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED); + crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED; } /** @@ -305,8 +305,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, int rc = 0; BUG_ON(!crypt_stat || !crypt_stat->tfm - || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_STRUCT_INITIALIZED)); + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n", crypt_stat->key_size); @@ -429,10 +428,10 @@ static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx, goto out; } } else { - rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, - lower_inode, - lower_page_idx); - if (rc) { + *lower_page = grab_cache_page(lower_inode->i_mapping, + lower_page_idx); + if (!(*lower_page)) { + rc = -EINVAL; ecryptfs_printk( KERN_ERR, "Error attempting to grab and map " "lower page with index [0x%.16x]; rc = [%d]\n", @@ -485,7 +484,7 @@ int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx) lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host); inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host); crypt_stat = &inode_info->crypt_stat; - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode, ctx->param.lower_file); if (rc) @@ -617,7 +616,7 @@ int ecryptfs_decrypt_page(struct file *file, struct page *page) crypt_stat = &(ecryptfs_inode_to_private( page->mapping->host)->crypt_stat); lower_inode = ecryptfs_inode_to_lower(page->mapping->host); - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_do_readpage(file, page, page->index); if (rc) ecryptfs_printk(KERN_ERR, "Error attempting to copy " @@ -628,7 +627,7 @@ int ecryptfs_decrypt_page(struct file *file, struct page *page) num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; base_extent = (page->index * num_extents_per_page); lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache, - SLAB_KERNEL); + GFP_KERNEL); if (!lower_page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Error getting page for encrypted " @@ -828,9 +827,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) mutex_unlock(&crypt_stat->cs_tfm_mutex); goto out; } - crypto_blkcipher_set_flags(crypt_stat->tfm, - (ECRYPTFS_DEFAULT_CHAINING_MODE - | CRYPTO_TFM_REQ_WEAK_KEY)); + crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); mutex_unlock(&crypt_stat->cs_tfm_mutex); rc = 0; out: @@ -865,7 +862,10 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } else crypt_stat->header_extent_size = PAGE_CACHE_SIZE; - crypt_stat->num_header_extents_at_front = 1; + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + crypt_stat->num_header_extents_at_front = 0; + else + crypt_stat->num_header_extents_at_front = 1; } /** @@ -881,7 +881,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat) BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE); BUG_ON(crypt_stat->iv_bytes <= 0); - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) { + if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Session key not valid; " "cannot generate root IV\n"); @@ -898,8 +898,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat) out: if (rc) { memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes); - ECRYPTFS_SET_FLAG(crypt_stat->flags, - ECRYPTFS_SECURITY_WARNING); + crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING; } return rc; } @@ -907,7 +906,7 @@ out: static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) { get_random_bytes(crypt_stat->key, crypt_stat->key_size); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags |= ECRYPTFS_KEY_VALID; ecryptfs_compute_root_iv(crypt_stat); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n"); @@ -916,6 +915,22 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) } } +/** + * ecryptfs_copy_mount_wide_flags_to_inode_flags + * + * This function propagates the mount-wide flags to individual inode + * flags. + */ +static void ecryptfs_copy_mount_wide_flags_to_inode_flags( + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) + crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED; +} + /** * ecryptfs_set_default_crypt_stat_vals * @crypt_stat @@ -926,10 +941,12 @@ static void ecryptfs_set_default_crypt_stat_vals( struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_mount_crypt_stat *mount_crypt_stat) { + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); ecryptfs_set_default_sizes(crypt_stat); strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER); crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES; - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); crypt_stat->file_version = ECRYPTFS_FILE_VERSION; crypt_stat->mount_crypt_stat = mount_crypt_stat; } @@ -969,8 +986,10 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) if (mount_crypt_stat->global_auth_tok) { ecryptfs_printk(KERN_DEBUG, "Initializing context for new " "file using mount_crypt_stat\n"); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags |= ECRYPTFS_ENCRYPTED; + crypt_stat->flags |= ECRYPTFS_KEY_VALID; + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++], mount_crypt_stat->global_auth_tok_sig, ECRYPTFS_SIG_SIZE_HEX); @@ -1003,7 +1022,7 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) * * Returns one if marker found; zero if not found */ -int contains_ecryptfs_marker(char *data) +static int contains_ecryptfs_marker(char *data) { u32 m_1, m_2; @@ -1029,7 +1048,8 @@ struct ecryptfs_flag_map_elem { /* Add support for additional flags by adding elements here. */ static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = { {0x00000001, ECRYPTFS_ENABLE_HMAC}, - {0x00000002, ECRYPTFS_ENCRYPTED} + {0x00000002, ECRYPTFS_ENCRYPTED}, + {0x00000004, ECRYPTFS_METADATA_IN_XATTR} }; /** @@ -1052,11 +1072,9 @@ static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat, for (i = 0; i < ((sizeof(ecryptfs_flag_map) / sizeof(struct ecryptfs_flag_map_elem))); i++) if (flags & ecryptfs_flag_map[i].file_flag) { - ECRYPTFS_SET_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag); + crypt_stat->flags |= ecryptfs_flag_map[i].local_flag; } else - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag); + crypt_stat->flags &= ~(ecryptfs_flag_map[i].local_flag); /* Version is in top 8 bits of the 32-bit flag vector */ crypt_stat->file_version = ((flags >> 24) & 0xFF); (*bytes_read) = 4; @@ -1093,8 +1111,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, for (i = 0; i < ((sizeof(ecryptfs_flag_map) / sizeof(struct ecryptfs_flag_map_elem))); i++) - if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag)) + if (crypt_stat->flags & ecryptfs_flag_map[i].local_flag) flags |= ecryptfs_flag_map[i].file_flag; /* Version is in top 8 bits of the 32-bit flag vector */ flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000); @@ -1189,8 +1206,8 @@ int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) * * Returns zero on success; non-zero otherwise */ -int ecryptfs_read_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt) +static int ecryptfs_read_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt) { struct file *lower_file; mm_segment_t oldfs; @@ -1219,9 +1236,25 @@ out: return rc; } -static void -write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat, - size_t *written) +int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt) +{ + int rc; + + rc = ecryptfs_read_header_region(data, dentry, mnt); + if (rc) + goto out; + if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) + rc = -EINVAL; +out: + return rc; +} + + +void +ecryptfs_write_header_metadata(char *virt, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *written) { u32 header_extent_size; u16 num_header_extents_at_front; @@ -1270,9 +1303,9 @@ struct kmem_cache *ecryptfs_header_cache_2; * * Returns zero on success */ -int ecryptfs_write_headers_virt(char *page_virt, - struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry) +static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry) { int rc; size_t written; @@ -1283,7 +1316,8 @@ int ecryptfs_write_headers_virt(char *page_virt, offset += written; write_ecryptfs_flags((page_virt + offset), crypt_stat, &written); offset += written; - write_header_metadata((page_virt + offset), crypt_stat, &written); + ecryptfs_write_header_metadata((page_virt + offset), crypt_stat, + &written); offset += written; rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat, ecryptfs_dentry, &written, @@ -1291,11 +1325,70 @@ int ecryptfs_write_headers_virt(char *page_virt, if (rc) ecryptfs_printk(KERN_WARNING, "Error generating key packet " "set; rc = [%d]\n", rc); + if (size) { + offset += written; + *size = offset; + } + return rc; +} + +static int ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, + struct file *lower_file, + char *page_virt) +{ + mm_segment_t oldfs; + int current_header_page; + int header_pages; + ssize_t size; + int rc = 0; + + lower_file->f_pos = 0; + oldfs = get_fs(); + set_fs(get_ds()); + size = vfs_write(lower_file, (char __user *)page_virt, PAGE_CACHE_SIZE, + &lower_file->f_pos); + if (size < 0) { + rc = (int)size; + printk(KERN_ERR "Error attempting to write lower page; " + "rc = [%d]\n", rc); + set_fs(oldfs); + goto out; + } + header_pages = ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + / PAGE_CACHE_SIZE); + memset(page_virt, 0, PAGE_CACHE_SIZE); + current_header_page = 1; + while (current_header_page < header_pages) { + size = vfs_write(lower_file, (char __user *)page_virt, + PAGE_CACHE_SIZE, &lower_file->f_pos); + if (size < 0) { + rc = (int)size; + printk(KERN_ERR "Error attempting to write lower page; " + "rc = [%d]\n", rc); + set_fs(oldfs); + goto out; + } + current_header_page++; + } + set_fs(oldfs); +out: + return rc; +} + +static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, + struct ecryptfs_crypt_stat *crypt_stat, + char *page_virt, size_t size) +{ + int rc; + + rc = ecryptfs_setxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, page_virt, + size, 0); return rc; } /** - * ecryptfs_write_headers + * ecryptfs_write_metadata * @lower_file: The lower file struct, which was returned from dentry_open * * Write the file headers out. This will likely involve a userspace @@ -1306,22 +1399,18 @@ int ecryptfs_write_headers_virt(char *page_virt, * * Returns zero on success; non-zero on error */ -int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, + struct file *lower_file) { - mm_segment_t oldfs; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt; - int current_header_page; - int header_pages; + size_t size; int rc = 0; crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; - if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_ENCRYPTED))) { - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_KEY_VALID)) { + if (likely(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { ecryptfs_printk(KERN_DEBUG, "Key is " "invalid; bailing out\n"); rc = -EINVAL; @@ -1334,54 +1423,42 @@ int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, goto out; } /* Released in this function */ - page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER); + page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); if (!page_virt) { ecryptfs_printk(KERN_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } - memset(page_virt, 0, PAGE_CACHE_SIZE); - rc = ecryptfs_write_headers_virt(page_virt, crypt_stat, - ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, + ecryptfs_dentry); if (unlikely(rc)) { ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); memset(page_virt, 0, PAGE_CACHE_SIZE); goto out_free; } - ecryptfs_printk(KERN_DEBUG, - "Writing key packet set to underlying file\n"); - lower_file->f_pos = 0; - oldfs = get_fs(); - set_fs(get_ds()); - ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" - "write() w/ header page; lower_file->f_pos = " - "[0x%.16x]\n", lower_file->f_pos); - lower_file->f_op->write(lower_file, (char __user *)page_virt, - PAGE_CACHE_SIZE, &lower_file->f_pos); - header_pages = ((crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front) - / PAGE_CACHE_SIZE); - memset(page_virt, 0, PAGE_CACHE_SIZE); - current_header_page = 1; - while (current_header_page < header_pages) { - ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" - "write() w/ zero'd page; lower_file->f_pos = " - "[0x%.16x]\n", lower_file->f_pos); - lower_file->f_op->write(lower_file, (char __user *)page_virt, - PAGE_CACHE_SIZE, &lower_file->f_pos); - current_header_page++; + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, + crypt_stat, page_virt, + size); + else + rc = ecryptfs_write_metadata_to_contents(crypt_stat, lower_file, + page_virt); + if (rc) { + printk(KERN_ERR "Error writing metadata out to lower file; " + "rc = [%d]\n", rc); + goto out_free; } - set_fs(oldfs); - ecryptfs_printk(KERN_DEBUG, - "Done writing key packet set to underlying file.\n"); out_free: kmem_cache_free(ecryptfs_header_cache_0, page_virt); out: return rc; } +#define ECRYPTFS_DONT_VALIDATE_HEADER_SIZE 0 +#define ECRYPTFS_VALIDATE_HEADER_SIZE 1 static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, - char *virt, int *bytes_read) + char *virt, int *bytes_read, + int validate_header_size) { int rc = 0; u32 header_extent_size; @@ -1396,9 +1473,10 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, crypt_stat->num_header_extents_at_front = (int)num_header_extents_at_front; (*bytes_read) = 6; - if ((crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front) - < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { + if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) + && ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Invalid header extent size: " "[%d]\n", crypt_stat->header_extent_size); @@ -1429,7 +1507,8 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) */ static int ecryptfs_read_headers_virt(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry) + struct dentry *ecryptfs_dentry, + int validate_header_size) { int rc = 0; int offset; @@ -1463,7 +1542,7 @@ static int ecryptfs_read_headers_virt(char *page_virt, offset += bytes_read; if (crypt_stat->file_version >= 1) { rc = parse_header_metadata(crypt_stat, (page_virt + offset), - &bytes_read); + &bytes_read, validate_header_size); if (rc) { ecryptfs_printk(KERN_WARNING, "Error reading header " "metadata; rc = [%d]\n", rc); @@ -1478,12 +1557,60 @@ out: } /** - * ecryptfs_read_headers + * ecryptfs_read_xattr_region + * + * Attempts to read the crypto metadata from the extended attribute + * region of the lower file. + */ +int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry) +{ + ssize_t size; + int rc = 0; + + size = ecryptfs_getxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, + page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); + if (size < 0) { + printk(KERN_DEBUG "Error attempting to read the [%s] " + "xattr from the lower file; return value = [%zd]\n", + ECRYPTFS_XATTR_NAME, size); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +int ecryptfs_read_and_validate_xattr_region(char *page_virt, + struct dentry *ecryptfs_dentry) +{ + int rc; + + rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry); + if (rc) + goto out; + if (!contains_ecryptfs_marker(page_virt + ECRYPTFS_FILE_SIZE_BYTES)) { + printk(KERN_WARNING "Valid data found in [%s] xattr, but " + "the marker is invalid\n", ECRYPTFS_XATTR_NAME); + rc = -EINVAL; + } +out: + return rc; +} + +/** + * ecryptfs_read_metadata + * + * Common entry point for reading file metadata. From here, we could + * retrieve the header information from the header region of the file, + * the xattr region of the file, or some other repostory that is + * stored separately from the file itself. The current implementation + * supports retrieving the metadata information from the file contents + * and from the xattr region. * * Returns zero if valid headers found and parsed; non-zero otherwise */ -int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, + struct file *lower_file) { int rc = 0; char *page_virt = NULL; @@ -1491,9 +1618,14 @@ int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, ssize_t bytes_read; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); /* Read the first page from the underlying file */ - page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER); + page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER); if (!page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n"); @@ -1512,11 +1644,36 @@ int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, goto out; } rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, - ecryptfs_dentry); + ecryptfs_dentry, + ECRYPTFS_VALIDATE_HEADER_SIZE); if (rc) { - ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not " - "found\n"); - rc = -EINVAL; + rc = ecryptfs_read_xattr_region(page_virt, + ecryptfs_dentry); + if (rc) { + printk(KERN_DEBUG "Valid eCryptfs headers not found in " + "file header region or xattr region\n"); + rc = -EINVAL; + goto out; + } + rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, + ecryptfs_dentry, + ECRYPTFS_DONT_VALIDATE_HEADER_SIZE); + if (rc) { + printk(KERN_DEBUG "Valid eCryptfs headers not found in " + "file xattr region either\n"); + rc = -EINVAL; + } + if (crypt_stat->mount_crypt_stat->flags + & ECRYPTFS_XATTR_METADATA_ENABLED) { + crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; + } else { + printk(KERN_WARNING "Attempt to access file with " + "crypto metadata only in the extended attribute " + "region, but eCryptfs was mounted without " + "xattr support enabled. eCryptfs will not treat " + "this like an encrypted file.\n"); + rc = -EINVAL; + } } out: if (page_virt) {