[kernel] r13328 - in dists/lenny-security/linux-2.6/debian: . patches/bugfix/all patches/series

Dann Frazier dannf at alioth.debian.org
Sat Apr 4 16:39:33 UTC 2009


Author: dannf
Date: Sat Apr  4 16:39:31 2009
New Revision: 13328

Log:
ecryptfs: Allocate a variable number of pages for file headers
(CVE-2009-0787)

Added:
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-allocate-a-variable-number-of-pages-for-file-headers.patch
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-fix-mem-corruption-when-storing-crypto-info-in-xattrs.patch
Modified:
   dists/lenny-security/linux-2.6/debian/changelog
   dists/lenny-security/linux-2.6/debian/patches/series/15lenny1

Modified: dists/lenny-security/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny-security/linux-2.6/debian/changelog	(original)
+++ dists/lenny-security/linux-2.6/debian/changelog	Sat Apr  4 16:39:31 2009
@@ -2,6 +2,8 @@
 
   * copy_process: fix CLONE_PARENT && parent_exec_id interaction
     (CVE-2009-0028)
+  * ecryptfs: Allocate a variable number of pages for file headers
+    (CVE-2009-0787)
 
  -- dann frazier <dannf at debian.org>  Fri, 03 Apr 2009 19:12:51 -0600
 

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-allocate-a-variable-number-of-pages-for-file-headers.patch
==============================================================================
--- (empty file)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-allocate-a-variable-number-of-pages-for-file-headers.patch	Sat Apr  4 16:39:31 2009
@@ -0,0 +1,143 @@
+commit 8faece5f906725c10e7a1f6caf84452abadbdc7b
+Author: Tyler Hicks <tyhicks at linux.vnet.ibm.com>
+Date:   Fri Mar 20 01:25:09 2009 -0500
+
+    eCryptfs: Allocate a variable number of pages for file headers
+    
+    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>
+
+Adjusted to apply to Debian's 2.6.26 by dann frazier <dannf at debian.org>
+
+diff -urpN linux-source-2.6.26.orig/fs/ecryptfs/crypto.c linux-source-2.6.26/fs/ecryptfs/crypto.c
+--- linux-source-2.6.26.orig/fs/ecryptfs/crypto.c	2009-04-04 10:32:41.000000000 -0600
++++ linux-source-2.6.26/fs/ecryptfs/crypto.c	2009-04-04 10:33:51.000000000 -0600
+@@ -1317,14 +1317,13 @@ static int ecryptfs_write_headers_virt(c
+ }
+ 
+ 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__,
+@@ -1334,7 +1333,6 @@ ecryptfs_write_metadata_to_contents(stru
+ 
+ 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;
+@@ -1344,6 +1342,17 @@ ecryptfs_write_metadata_to_xattr(struct 
+ 	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
+@@ -1360,7 +1369,9 @@ int ecryptfs_write_metadata(struct dentr
+ {
+ 	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;
+ 
+@@ -1376,33 +1387,35 @@ int ecryptfs_write_metadata(struct dentr
+ 		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;
+ }

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-fix-mem-corruption-when-storing-crypto-info-in-xattrs.patch
==============================================================================
--- (empty file)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ecryptfs-fix-mem-corruption-when-storing-crypto-info-in-xattrs.patch	Sat Apr  4 16:39:31 2009
@@ -0,0 +1,90 @@
+commit 87b811c3f96559e466403e22b1fa99d472571625
+Author: Eric Sandeen <sandeen at redhat.com>
+Date:   Wed Oct 29 14:01:08 2008 -0700
+
+    ecryptfs: fix memory corruption when storing crypto info in xattrs
+    
+    When ecryptfs allocates space to write crypto headers into, before copying
+    it out to file headers or to xattrs, it looks at the value of
+    crypt_stat->num_header_bytes_at_front to determine how much space it
+    needs.  This is also used as the file offset to the actual encrypted data,
+    so for xattr-stored crypto info, the value was zero.
+    
+    So, we kzalloc'd 0 bytes, and then ran off to write to that memory.
+    (Which returned as ZERO_SIZE_PTR, so we explode quickly).
+    
+    The right answer is to always allocate a page to write into; the current
+    code won't ever write more than that (this is enforced by the
+    (PAGE_CACHE_SIZE - offset) length in the call to
+    ecryptfs_generate_key_packet_set).  To be explicit about this, we now send
+    in a "max" parameter, rather than magically using PAGE_CACHE_SIZE there.
+    
+    Also, since the pointer we pass down the callchain eventually gets the
+    virt_to_page() treatment, we should be using a alloc_page variant, not
+    kzalloc (see also 7fcba054373d5dfc43d26e243a5c9b92069972ee)
+    
+    Signed-off-by: Eric Sandeen <sandeen at redhat.com>
+    Acked-by: Michael Halcrow <mhalcrow at us.ibm.com>
+    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+    Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+
+Adjusted to apply to Debian's 2.6.26 by dann frazier <dannf at debian.org>
+
+diff -urpN linux-source-2.6.26.orig/fs/ecryptfs/crypto.c linux-source-2.6.26/fs/ecryptfs/crypto.c
+--- linux-source-2.6.26.orig/fs/ecryptfs/crypto.c	2009-03-25 17:20:38.000000000 -0600
++++ linux-source-2.6.26/fs/ecryptfs/crypto.c	2009-04-04 10:32:41.000000000 -0600
+@@ -1258,6 +1258,7 @@ struct kmem_cache *ecryptfs_header_cache
+ /**
+  * ecryptfs_write_headers_virt
+  * @page_virt: The virtual address to write the headers to
++ * @max: The size of memory allocated at page_virt
+  * @size: Set to the number of bytes written by this function
+  * @crypt_stat: The cryptographic context
+  * @ecryptfs_dentry: The eCryptfs dentry
+@@ -1285,7 +1286,8 @@ struct kmem_cache *ecryptfs_header_cache
+  *
+  * Returns zero on success
+  */
+-static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,
++static int ecryptfs_write_headers_virt(char *page_virt, size_t max,
++				       size_t *size,
+ 				       struct ecryptfs_crypt_stat *crypt_stat,
+ 				       struct dentry *ecryptfs_dentry)
+ {
+@@ -1303,7 +1305,7 @@ static int ecryptfs_write_headers_virt(c
+ 	offset += written;
+ 	rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
+ 					      ecryptfs_dentry, &written,
+-					      PAGE_CACHE_SIZE - offset);
++					      max - offset);
+ 	if (rc)
+ 		ecryptfs_printk(KERN_WARNING, "Error generating key packet "
+ 				"set; rc = [%d]\n", rc);
+@@ -1375,14 +1377,14 @@ int ecryptfs_write_metadata(struct dentr
+ 		goto out;
+ 	}
+ 	/* Released in this function */
+-	virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
++	virt = (char *)get_zeroed_page(GFP_KERNEL);
+ 	if (!virt) {
+ 		printk(KERN_ERR "%s: Out of memory\n", __func__);
+ 		rc = -ENOMEM;
+ 		goto out;
+ 	}
+-	rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
+-					 ecryptfs_dentry);
++	rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size,
++					 crypt_stat, ecryptfs_dentry);
+ 	if (unlikely(rc)) {
+ 		printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
+ 		       __func__, rc);
+@@ -1400,8 +1402,7 @@ int ecryptfs_write_metadata(struct dentr
+ 		goto out_free;
+ 	}
+ out_free:
+-	memset(virt, 0, crypt_stat->num_header_bytes_at_front);
+-	kfree(virt);
++	free_page((unsigned long)virt);
+ out:
+ 	return rc;
+ }

Modified: dists/lenny-security/linux-2.6/debian/patches/series/15lenny1
==============================================================================
--- dists/lenny-security/linux-2.6/debian/patches/series/15lenny1	(original)
+++ dists/lenny-security/linux-2.6/debian/patches/series/15lenny1	Sat Apr  4 16:39:31 2009
@@ -1 +1,3 @@
 + bugfix/all/copy_process-fix-CLONE_PARENT-and-parent_exec_id-interaction.patch
++ bugfix/all/ecryptfs-fix-mem-corruption-when-storing-crypto-info-in-xattrs.patch
++ bugfix/all/ecryptfs-allocate-a-variable-number-of-pages-for-file-headers.patch



More information about the Kernel-svn-changes mailing list