LP #345544 - (CVE-2009-0787) ecryptfs stores ram contents in plaintext in the container as padding

Stefan Bader stefan.bader at canonical.com
Mon Mar 23 12:55:06 GMT 2009


Looks ok to me. ACK

Tim Gardner wrote:
> From 2948c4e71c47eae1de4a259eba1e2af778cbd052 Mon Sep 17 00:00:00 2001
> From: Tyler Hicks <tyhicks at linux.vnet.ibm.com>
> Date: Fri, 20 Mar 2009 01:25:09 -0500
> Subject: [PATCH] eCryptfs: Allocate a variable number of pages for file headers (CVE-2009-0787)
> 
> Bug: #345544
> 
> When allocating the memory used to store the eCryptfs header contents, a
> single, zeroed page was being allocated with get_zeroed_page().
> However, the size of an eCryptfs header is either PAGE_CACHE_SIZE or
> ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE (8192), whichever is larger, and is
> stored in the file's private_data->crypt_stat->num_header_bytes_at_front
> field.
> 
> ecryptfs_write_metadata_to_contents() was using
> num_header_bytes_at_front to decide how many bytes should be written to
> the lower filesystem for the file header.  Unfortunately, at least 8K
> was being written from the page, despite the chance of the single,
> zeroed page being smaller than 8K.  This resulted in random areas of
> kernel memory being written between the 0x1000 and 0x1FFF bytes offsets
> in the eCryptfs file headers if PAGE_SIZE was 4K.
> 
> This patch allocates a variable number of pages, calculated with
> num_header_bytes_at_front, and passes the number of allocated pages
> along to ecryptfs_write_metadata_to_contents().
> 
> Thanks to Florian Streibelt for reporting the data leak and working with
> me to find the problem.  2.6.28 is the only kernel release with this
> vulnerability.  Corresponds to CVE-2009-0787
> 
> Signed-off-by: Tyler Hicks <tyhicks at linux.vnet.ibm.com>
> Acked-by: Dustin Kirkland <kirkland at canonical.com>
> Reviewed-by: Eric Sandeen <sandeen at redhat.com>
> Reviewed-by: Eugene Teo <eugeneteo at kernel.sg>
> Cc: Greg KH <greg at kroah.com>
> Cc: dann frazier <dannf at dannf.org>
> Cc: Serge E. Hallyn <serue at us.ibm.com>
> Cc: Florian Streibelt <florian at f-streibelt.de>
> Cc: stable at kernel.org
> Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
> (cherry picked from commit 8faece5f906725c10e7a1f6caf84452abadbdc7b)
> 
> Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
> ---
>  fs/ecryptfs/crypto.c |   39 ++++++++++++++++++++++++++-------------
>  1 files changed, 26 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
> index 1607e09..8b65f28 100644
> --- a/fs/ecryptfs/crypto.c
> +++ b/fs/ecryptfs/crypto.c
> @@ -1324,14 +1324,13 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max,
>  }
>  
>  static int
> -ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
> -				    struct dentry *ecryptfs_dentry,
> -				    char *virt)
> +ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry,
> +				    char *virt, size_t virt_len)
>  {
>  	int rc;
>  
>  	rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
> -				  0, crypt_stat->num_header_bytes_at_front);
> +				  0, virt_len);
>  	if (rc)
>  		printk(KERN_ERR "%s: Error attempting to write header "
>  		       "information to lower file; rc = [%d]\n", __func__,
> @@ -1341,7 +1340,6 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
>  
>  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;
> @@ -1351,6 +1349,17 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
>  	return rc;
>  }
>  
> +static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask,
> +					       unsigned int order)
> +{
> +	struct page *page;
> +
> +	page = alloc_pages(gfp_mask | __GFP_ZERO, order);
> +	if (page)
> +		return (unsigned long) page_address(page);
> +	return 0;
> +}
> +
>  /**
>   * ecryptfs_write_metadata
>   * @ecryptfs_dentry: The eCryptfs dentry
> @@ -1367,7 +1376,9 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
>  {
>  	struct ecryptfs_crypt_stat *crypt_stat =
>  		&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
> +	unsigned int order;
>  	char *virt;
> +	size_t virt_len;
>  	size_t size = 0;
>  	int rc = 0;
>  
> @@ -1383,33 +1394,35 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
>  		rc = -EINVAL;
>  		goto out;
>  	}
> +	virt_len = crypt_stat->num_header_bytes_at_front;
> +	order = get_order(virt_len);
>  	/* Released in this function */
> -	virt = (char *)get_zeroed_page(GFP_KERNEL);
> +	virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order);
>  	if (!virt) {
>  		printk(KERN_ERR "%s: Out of memory\n", __func__);
>  		rc = -ENOMEM;
>  		goto out;
>  	}
> -	rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size,
> -					 crypt_stat, ecryptfs_dentry);
> +	rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat,
> +					 ecryptfs_dentry);
>  	if (unlikely(rc)) {
>  		printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
>  		       __func__, rc);
>  		goto out_free;
>  	}
>  	if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
> -		rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
> -						      crypt_stat, virt, size);
> +		rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt,
> +						      size);
>  	else
> -		rc = ecryptfs_write_metadata_to_contents(crypt_stat,
> -							 ecryptfs_dentry, virt);
> +		rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt,
> +							 virt_len);
>  	if (rc) {
>  		printk(KERN_ERR "%s: Error writing metadata out to lower file; "
>  		       "rc = [%d]\n", __func__, rc);
>  		goto out_free;
>  	}
>  out_free:
> -	free_page((unsigned long)virt);
> +	free_pages((unsigned long)virt, order);
>  out:
>  	return rc;
>  }


-- 

When all other means of communication fail, try words!





More information about the kernel-team mailing list