Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+35 −63
Original line number Original line Diff line number Diff line
@@ -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)
	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,


	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,
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,
 * 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)
			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,
	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,
 */
 */
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;
}
}


/**
/**
+1 −2
Original line number Original line Diff line number Diff line
@@ -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;
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;
+3 −5
Original line number Original line Diff line number Diff line
@@ -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)
 * @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,
{
{
	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;


+0 −5
Original line number Original line Diff line number Diff line
@@ -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",
+12 −9
Original line number Original line Diff line number Diff line
@@ -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,
		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,
		} 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),