Commit cc11beff authored by Michael Halcrow's avatar Michael Halcrow Committed by Linus Torvalds

eCryptfs: track header bytes rather than extents

Remove internal references to header extents; just keep track of header bytes
instead.  Headers can easily span multiple pages with the recent persistent
file changes.
Signed-off-by: default avatarMichael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7896b631
...@@ -379,8 +379,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -379,8 +379,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
struct ecryptfs_crypt_stat *crypt_stat) struct ecryptfs_crypt_stat *crypt_stat)
{ {
(*offset) = ((crypt_stat->extent_size (*offset) = (crypt_stat->num_header_bytes_at_front
* crypt_stat->num_header_extents_at_front)
+ (crypt_stat->extent_size * extent_num)); + (crypt_stat->extent_size * extent_num));
} }
...@@ -842,15 +841,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) ...@@ -842,15 +841,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
set_extent_mask_and_shift(crypt_stat); set_extent_mask_and_shift(crypt_stat);
crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
crypt_stat->num_header_extents_at_front = 0; crypt_stat->num_header_bytes_at_front = 0;
else { else {
if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
crypt_stat->num_header_extents_at_front = crypt_stat->num_header_bytes_at_front =
(ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
/ crypt_stat->extent_size);
else else
crypt_stat->num_header_extents_at_front = crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
(PAGE_CACHE_SIZE / crypt_stat->extent_size);
} }
} }
...@@ -1236,7 +1233,8 @@ ecryptfs_write_header_metadata(char *virt, ...@@ -1236,7 +1233,8 @@ ecryptfs_write_header_metadata(char *virt,
header_extent_size = (u32)crypt_stat->extent_size; header_extent_size = (u32)crypt_stat->extent_size;
num_header_extents_at_front = num_header_extents_at_front =
(u16)crypt_stat->num_header_extents_at_front; (u16)(crypt_stat->num_header_bytes_at_front
/ crypt_stat->extent_size);
header_extent_size = cpu_to_be32(header_extent_size); header_extent_size = cpu_to_be32(header_extent_size);
memcpy(virt, &header_extent_size, 4); memcpy(virt, &header_extent_size, 4);
virt += 4; virt += 4;
...@@ -1311,40 +1309,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, ...@@ -1311,40 +1309,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,
static int static int
ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
struct dentry *ecryptfs_dentry, struct dentry *ecryptfs_dentry,
char *page_virt) char *virt)
{ {
int current_header_page;
int header_pages;
int rc; int rc;
rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
0, PAGE_CACHE_SIZE); 0, crypt_stat->num_header_bytes_at_front);
if (rc) { if (rc)
printk(KERN_ERR "%s: Error attempting to write header " printk(KERN_ERR "%s: Error attempting to write header "
"information to lower file; rc = [%d]\n", __FUNCTION__, "information to lower file; rc = [%d]\n", __FUNCTION__,
rc); rc);
goto out;
}
header_pages = ((crypt_stat->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) {
loff_t offset;
offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
page_virt, offset,
PAGE_CACHE_SIZE))) {
printk(KERN_ERR "%s: Error attempting to write header "
"information to lower file; rc = [%d]\n",
__FUNCTION__, rc);
goto out;
}
current_header_page++;
}
out:
return rc; return rc;
} }
...@@ -1370,15 +1344,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, ...@@ -1370,15 +1344,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
* retrieved via a prompt. Exactly what happens at this point should * retrieved via a prompt. Exactly what happens at this point should
* be policy-dependent. * be policy-dependent.
* *
* TODO: Support header information spanning multiple pages
*
* Returns zero on success; non-zero on error * Returns zero on success; non-zero on error
*/ */
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
{ {
struct ecryptfs_crypt_stat *crypt_stat = struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
char *page_virt; char *virt;
size_t size = 0; size_t size = 0;
int rc = 0; int rc = 0;
...@@ -1389,40 +1361,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) ...@@ -1389,40 +1361,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
goto out; goto out;
} }
} else { } else {
printk(KERN_WARNING "%s: Encrypted flag not set\n",
__FUNCTION__);
rc = -EINVAL; rc = -EINVAL;
ecryptfs_printk(KERN_WARNING,
"Called with crypt_stat->encrypted == 0\n");
goto out; goto out;
} }
/* Released in this function */ /* Released in this function */
page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
if (!page_virt) { if (!virt) {
ecryptfs_printk(KERN_ERR, "Out of memory\n"); printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
ecryptfs_dentry); ecryptfs_dentry);
if (unlikely(rc)) { if (unlikely(rc)) {
ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
memset(page_virt, 0, PAGE_CACHE_SIZE); __FUNCTION__, rc);
goto out_free; goto out_free;
} }
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
crypt_stat, page_virt, crypt_stat, virt, size);
size);
else else
rc = ecryptfs_write_metadata_to_contents(crypt_stat, rc = ecryptfs_write_metadata_to_contents(crypt_stat,
ecryptfs_dentry, ecryptfs_dentry, virt);
page_virt);
if (rc) { if (rc) {
printk(KERN_ERR "Error writing metadata out to lower file; " printk(KERN_ERR "%s: Error writing metadata out to lower file; "
"rc = [%d]\n", rc); "rc = [%d]\n", __FUNCTION__, rc);
goto out_free; goto out_free;
} }
out_free: out_free:
kmem_cache_free(ecryptfs_header_cache_0, page_virt); memset(virt, 0, crypt_stat->num_header_bytes_at_front);
kfree(virt);
out: out:
return rc; return rc;
} }
...@@ -1442,16 +1413,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -1442,16 +1413,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
virt += sizeof(u32); virt += sizeof(u32);
memcpy(&num_header_extents_at_front, virt, sizeof(u16)); memcpy(&num_header_extents_at_front, virt, sizeof(u16));
num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front); num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
crypt_stat->num_header_extents_at_front = crypt_stat->num_header_bytes_at_front =
(int)num_header_extents_at_front; (((size_t)num_header_extents_at_front
* (size_t)header_extent_size));
(*bytes_read) = (sizeof(u32) + sizeof(u16)); (*bytes_read) = (sizeof(u32) + sizeof(u16));
if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
&& ((crypt_stat->extent_size && (crypt_stat->num_header_bytes_at_front
* crypt_stat->num_header_extents_at_front)
< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
rc = -EINVAL; rc = -EINVAL;
printk(KERN_WARNING "Invalid number of header extents: [%zd]\n", printk(KERN_WARNING "Invalid header size: [%zd]\n",
crypt_stat->num_header_extents_at_front); crypt_stat->num_header_bytes_at_front);
} }
return rc; return rc;
} }
...@@ -1466,7 +1437,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -1466,7 +1437,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
*/ */
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
{ {
crypt_stat->num_header_extents_at_front = 2; crypt_stat->num_header_bytes_at_front =
ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
} }
/** /**
......
...@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat { ...@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
u32 flags; u32 flags;
unsigned int file_version; unsigned int file_version;
size_t iv_bytes; size_t iv_bytes;
size_t num_header_extents_at_front; size_t num_header_bytes_at_front;
size_t extent_size; /* Data extent size; default is 4096 */ size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size; size_t key_size;
size_t extent_shift; size_t extent_shift;
...@@ -518,7 +518,6 @@ extern struct kmem_cache *ecryptfs_file_info_cache; ...@@ -518,7 +518,6 @@ extern struct kmem_cache *ecryptfs_file_info_cache;
extern struct kmem_cache *ecryptfs_dentry_info_cache; extern struct kmem_cache *ecryptfs_dentry_info_cache;
extern struct kmem_cache *ecryptfs_inode_info_cache; extern struct kmem_cache *ecryptfs_inode_info_cache;
extern struct kmem_cache *ecryptfs_sb_info_cache; extern struct kmem_cache *ecryptfs_sb_info_cache;
extern struct kmem_cache *ecryptfs_header_cache_0;
extern struct kmem_cache *ecryptfs_header_cache_1; extern struct kmem_cache *ecryptfs_header_cache_1;
extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_header_cache_2;
extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_xattr_cache;
......
...@@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_sb)->mount_crypt_stat; dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
file_size = ((crypt_stat->extent_size file_size = (crypt_stat->num_header_bytes_at_front
* crypt_stat->num_header_extents_at_front)
+ i_size_read(lower_dentry->d_inode)); + i_size_read(lower_dentry->d_inode));
else else
file_size = i_size_read(lower_dentry->d_inode); file_size = i_size_read(lower_dentry->d_inode);
...@@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) ...@@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
* @crypt_stat: Crypt_stat associated with file * @crypt_stat: Crypt_stat associated with file
* @upper_size: Size of the upper file * @upper_size: Size of the upper file
* *
* Calculate the requried size of the lower file based on the * Calculate the required size of the lower file based on the
* specified size of the upper file. This calculation is based on the * specified size of the upper file. This calculation is based on the
* number of headers in the underlying file and the extent size. * number of headers in the underlying file and the extent size.
* *
...@@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
{ {
loff_t lower_size; loff_t lower_size;
lower_size = (crypt_stat->extent_size lower_size = crypt_stat->num_header_bytes_at_front;
* crypt_stat->num_header_extents_at_front);
if (upper_size != 0) { if (upper_size != 0) {
loff_t num_extents; loff_t num_extents;
......
...@@ -653,11 +653,6 @@ static struct ecryptfs_cache_info { ...@@ -653,11 +653,6 @@ static struct ecryptfs_cache_info {
.name = "ecryptfs_sb_cache", .name = "ecryptfs_sb_cache",
.size = sizeof(struct ecryptfs_sb_info), .size = sizeof(struct ecryptfs_sb_info),
}, },
{
.cache = &ecryptfs_header_cache_0,
.name = "ecryptfs_headers_0",
.size = PAGE_CACHE_SIZE,
},
{ {
.cache = &ecryptfs_header_cache_1, .cache = &ecryptfs_header_cache_1,
.name = "ecryptfs_headers_1", .name = "ecryptfs_headers_1",
......
...@@ -100,13 +100,14 @@ static void set_header_info(char *page_virt, ...@@ -100,13 +100,14 @@ static void set_header_info(char *page_virt,
struct ecryptfs_crypt_stat *crypt_stat) struct ecryptfs_crypt_stat *crypt_stat)
{ {
size_t written; size_t written;
int save_num_header_extents_at_front = size_t save_num_header_bytes_at_front =
crypt_stat->num_header_extents_at_front; crypt_stat->num_header_bytes_at_front;
crypt_stat->num_header_extents_at_front = 1; crypt_stat->num_header_bytes_at_front =
ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
crypt_stat->num_header_extents_at_front = crypt_stat->num_header_bytes_at_front =
save_num_header_extents_at_front; save_num_header_bytes_at_front;
} }
/** /**
...@@ -132,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, ...@@ -132,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
loff_t view_extent_num = ((((loff_t)page->index) loff_t view_extent_num = ((((loff_t)page->index)
* num_extents_per_page) * num_extents_per_page)
+ extent_num_in_page); + extent_num_in_page);
size_t num_header_extents_at_front =
(crypt_stat->num_header_bytes_at_front
/ crypt_stat->extent_size);
if (view_extent_num < crypt_stat->num_header_extents_at_front) { if (view_extent_num < num_header_extents_at_front) {
/* This is a header extent */ /* This is a header extent */
char *page_virt; char *page_virt;
...@@ -155,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, ...@@ -155,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
} else { } else {
/* This is an encrypted data extent */ /* This is an encrypted data extent */
loff_t lower_offset = loff_t lower_offset =
((view_extent_num - ((view_extent_num * crypt_stat->extent_size)
crypt_stat->num_header_extents_at_front) - crypt_stat->num_header_bytes_at_front);
* crypt_stat->extent_size);
rc = ecryptfs_read_lower_page_segment( rc = ecryptfs_read_lower_page_segment(
page, (lower_offset >> PAGE_CACHE_SHIFT), page, (lower_offset >> PAGE_CACHE_SHIFT),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment