[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