[kernel] r9702 - in dists/etch-security/linux-2.6/debian: . patches/bugfix patches/series
Dann Frazier
dannf at alioth.debian.org
Thu Nov 8 04:01:43 UTC 2007
Author: dannf
Date: Thu Nov 8 04:01:42 2007
New Revision: 9702
Log:
* bugfix/sysfs_readdir-NULL-deref-1.patch,
bugfix/sysfs_readdir-NULL-deref-2.patch,
bugfix/sysfs-fix-condition-check.patch
[SECURITY] Fix potential NULL pointer dereference which can lead to
a local DoS (kernel oops)
See CVE-2007-3104
Added:
dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs-fix-condition-check.patch
dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-1.patch
dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-2.patch
dists/etch-security/linux-2.6/debian/patches/series/13etch5
Modified:
dists/etch-security/linux-2.6/debian/changelog
Modified: dists/etch-security/linux-2.6/debian/changelog
==============================================================================
--- dists/etch-security/linux-2.6/debian/changelog (original)
+++ dists/etch-security/linux-2.6/debian/changelog Thu Nov 8 04:01:42 2007
@@ -1,3 +1,14 @@
+linux-2.6 (2.6.18.dfsg.1-13etch5) UNRELEASED-stable-security; urgency=high
+
+ * bugfix/sysfs_readdir-NULL-deref-1.patch,
+ bugfix/sysfs_readdir-NULL-deref-2.patch,
+ bugfix/sysfs-fix-condition-check.patch
+ [SECURITY] Fix potential NULL pointer dereference which can lead to
+ a local DoS (kernel oops)
+ See CVE-2007-3104
+
+ -- dann frazier <dannf at debian.org> Wed, 07 Nov 2007 17:18:15 -0700
+
linux-2.6 (2.6.18.dfsg.1-13etch4) stable-security; urgency=high
[ Bastian Blank ]
Added: dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs-fix-condition-check.patch
==============================================================================
--- (empty file)
+++ dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs-fix-condition-check.patch Thu Nov 8 04:01:42 2007
@@ -0,0 +1,29 @@
+From: Tejun Heo <htejun at gmail.com>
+Date: Mon, 11 Jun 2007 05:03:27 +0000 (+0900)
+Subject: sysfs: fix condition check in sysfs_drop_dentry()
+X-Git-Tag: v2.6.22-rc5~46
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6aa054aadfea613a437ad0b15d38eca2b963fc0a
+
+sysfs: fix condition check in sysfs_drop_dentry()
+
+The condition check doesn't make much sense as it basically always
+succeeds. This causes NULL dereferencing on certain cases. It seems
+that parentheses are put in the wrong place. Fix it.
+
+Signed-off-by: Tejun Heo <htejun at gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+Adjusted to apply to Debian's 2.6.18 by dann frazier <dannf at hp.com>
+
+--- linux-source-2.6.18+2.6.22.y/fs/sysfs/inode.c.orig 2007-11-07 15:40:19.000000000 -0700
++++ linux-source-2.6.18+2.6.22.y/fs/sysfs/inode.c 2007-11-07 17:09:33.000000000 -0700
+@@ -236,7 +236,7 @@ void sysfs_drop_dentry(struct sysfs_dire
+ if (dentry) {
+ spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
+- if (!(d_unhashed(dentry) && dentry->d_inode)) {
++ if (!d_unhashed(dentry) && dentry->d_inode) {
+ dget_locked(dentry);
+ __d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
Added: dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-1.patch
==============================================================================
--- (empty file)
+++ dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-1.patch Thu Nov 8 04:01:42 2007
@@ -0,0 +1,112 @@
+From: Eric Sandeen <sandeen at sandeen.net>
+Date: Mon, 11 Jun 2007 05:02:45 +0000 (+0900)
+Subject: sysfs: store sysfs inode nrs in s_ino to avoid readdir oopses
+X-Git-Tag: v2.6.22-rc5~47
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.22.y.git;a=commitdiff_plain;h=dc351252b33f8fede396d6173dba117bcb933607
+
+sysfs: store sysfs inode nrs in s_ino to avoid readdir oopses
+
+Backport of
+ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc1/2.6.22-rc1-mm1/broken-out/gregkh-driver-sysfs-allocate-inode-number-using-ida.patch
+
+For regular files in sysfs, sysfs_readdir wants to traverse
+sysfs_dirent->s_dentry->d_inode->i_ino to get to the inode number.
+But, the dentry can be reclaimed under memory pressure, and there is
+no synchronization with readdir. This patch follows Tejun's scheme of
+allocating and storing an inode number in the new s_ino member of a
+sysfs_dirent, when dirents are created, and retrieving it from there
+for readdir, so that the pointer chain doesn't have to be traversed.
+
+Tejun's upstream patch uses a new-ish "ida" allocator which brings
+along some extra complexity; this -stable patch has a brain-dead
+incrementing counter which does not guarantee uniqueness, but because
+sysfs doesn't hash inodes as iunique expects, uniqueness wasn't
+guaranteed today anyway.
+
+Signed-off-by: Eric Sandeen <sandeen at redhat.com>
+Signed-off-by: Tejun Heo <htejun at gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <dannf at hp.com>
+
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/dir.c linux-source-2.6.18/fs/sysfs/dir.c
+--- linux-source-2.6.18.orig/fs/sysfs/dir.c 2006-09-19 21:42:06.000000000 -0600
++++ linux-source-2.6.18/fs/sysfs/dir.c 2007-11-07 15:31:11.000000000 -0700
+@@ -29,6 +29,14 @@ static struct dentry_operations sysfs_de
+ .d_iput = sysfs_d_iput,
+ };
+
++static unsigned int sysfs_inode_counter;
++ino_t sysfs_get_inum(void)
++{
++ if (unlikely(sysfs_inode_counter < 3))
++ sysfs_inode_counter = 3;
++ return sysfs_inode_counter++;
++}
++
+ /*
+ * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
+ */
+@@ -42,6 +50,7 @@ static struct sysfs_dirent * sysfs_new_d
+ return NULL;
+
+ memset(sd, 0, sizeof(*sd));
++ sd->s_ino = sysfs_get_inum();
+ atomic_set(&sd->s_count, 1);
+ atomic_set(&sd->s_event, 0);
+ INIT_LIST_HEAD(&sd->s_children);
+@@ -416,7 +425,7 @@ static int sysfs_readdir(struct file * f
+
+ switch (i) {
+ case 0:
+- ino = dentry->d_inode->i_ino;
++ ino = parent_sd->s_ino;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+ break;
+ filp->f_pos++;
+@@ -445,10 +454,7 @@ static int sysfs_readdir(struct file * f
+
+ name = sysfs_get_name(next);
+ len = strlen(name);
+- if (next->s_dentry)
+- ino = next->s_dentry->d_inode->i_ino;
+- else
+- ino = iunique(sysfs_sb, 2);
++ ino = next->s_ino;
+
+ if (filldir(dirent, name, len, filp->f_pos, ino,
+ dt_type(next)) < 0)
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/inode.c linux-source-2.6.18/fs/sysfs/inode.c
+--- linux-source-2.6.18.orig/fs/sysfs/inode.c 2006-09-19 21:42:06.000000000 -0600
++++ linux-source-2.6.18/fs/sysfs/inode.c 2007-11-07 15:30:13.000000000 -0700
+@@ -129,6 +129,7 @@ struct inode * sysfs_new_inode(mode_t mo
+ inode->i_mapping->a_ops = &sysfs_aops;
+ inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
+ inode->i_op = &sysfs_inode_operations;
++ inode->i_ino = sd->s_ino;
+ lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
+
+ if (sd->s_iattr) {
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/mount.c linux-source-2.6.18/fs/sysfs/mount.c
+--- linux-source-2.6.18.orig/fs/sysfs/mount.c 2006-09-19 21:42:06.000000000 -0600
++++ linux-source-2.6.18/fs/sysfs/mount.c 2007-11-07 15:30:13.000000000 -0700
+@@ -29,6 +29,7 @@ static struct sysfs_dirent sysfs_root =
+ .s_element = NULL,
+ .s_type = SYSFS_ROOT,
+ .s_iattr = NULL,
++ .s_ino = 1,
+ };
+
+ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
+diff -urpN linux-source-2.6.18.orig/include/linux/sysfs.h linux-source-2.6.18/include/linux/sysfs.h
+--- linux-source-2.6.18.orig/include/linux/sysfs.h 2006-09-19 21:42:06.000000000 -0600
++++ linux-source-2.6.18/include/linux/sysfs.h 2007-11-07 15:34:16.000000000 -0700
+@@ -72,6 +72,7 @@ struct sysfs_dirent {
+ void * s_element;
+ int s_type;
+ umode_t s_mode;
++ ino_t s_ino;
+ struct dentry * s_dentry;
+ struct iattr * s_iattr;
+ atomic_t s_event;
Added: dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-2.patch
==============================================================================
--- (empty file)
+++ dists/etch-security/linux-2.6/debian/patches/bugfix/sysfs_readdir-NULL-deref-2.patch Thu Nov 8 04:01:42 2007
@@ -0,0 +1,128 @@
+From: Tejun Heo <htejun at gmail.com>
+Date: Mon, 11 Jun 2007 05:04:01 +0000 (+0900)
+Subject: sysfs: fix race condition around sd->s_dentry, take#2
+X-Git-Tag: v2.6.22-rc5~45
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.22.y.git;a=commitdiff_plain;h=dd14cbc994709a1c5a64ed3621f583c49a27e521
+
+sysfs: fix race condition around sd->s_dentry, take#2
+
+Allowing attribute and symlink dentries to be reclaimed means
+sd->s_dentry can change dynamically. However, updates to the field
+are unsynchronized leading to race conditions. This patch adds
+sysfs_lock and use it to synchronize updates to sd->s_dentry.
+
+Due to the locking around ->d_iput, the check in sysfs_drop_dentry()
+is complex. sysfs_lock only protect sd->s_dentry pointer itself. The
+validity of the dentry is protected by dcache_lock, so whether dentry
+is alive or not can only be tested while holding both locks.
+
+This is minimal backport of sysfs_drop_dentry() rewrite in devel
+branch.
+
+Signed-off-by: Tejun Heo <htejun at gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <dannf at hp.com>
+
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/dir.c linux-source-2.6.18/fs/sysfs/dir.c
+--- linux-source-2.6.18.orig/fs/sysfs/dir.c 2007-11-07 15:44:57.000000000 -0700
++++ linux-source-2.6.18/fs/sysfs/dir.c 2007-11-07 15:38:57.000000000 -0700
+@@ -12,14 +12,26 @@
+ #include "sysfs.h"
+
+ DECLARE_RWSEM(sysfs_rename_sem);
++spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED;
+
+ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
+ {
+ struct sysfs_dirent * sd = dentry->d_fsdata;
+
+ if (sd) {
+- BUG_ON(sd->s_dentry != dentry);
+- sd->s_dentry = NULL;
++ /* sd->s_dentry is protected with sysfs_lock. This
++ * allows sysfs_drop_dentry() to dereference it.
++ */
++ spin_lock(&sysfs_lock);
++
++ /* The dentry might have been deleted or another
++ * lookup could have happened updating sd->s_dentry to
++ * point the new dentry. Ignore if it isn't pointing
++ * to this dentry.
++ */
++ if (sd->s_dentry == dentry)
++ sd->s_dentry = NULL;
++ spin_unlock(&sysfs_lock);
+ sysfs_put(sd);
+ }
+ iput(inode);
+@@ -218,7 +230,10 @@ static int sysfs_attach_attr(struct sysf
+ }
+
+ dentry->d_fsdata = sysfs_get(sd);
++ /* protect sd->s_dentry against sysfs_d_iput */
++ spin_lock(&sysfs_lock);
+ sd->s_dentry = dentry;
++ spin_unlock(&sysfs_lock);
+ error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init);
+ if (error) {
+ sysfs_put(sd);
+@@ -240,7 +255,10 @@ static int sysfs_attach_link(struct sysf
+ int err = 0;
+
+ dentry->d_fsdata = sysfs_get(sd);
++ /* protect sd->s_dentry against sysfs_d_iput */
++ spin_lock(&sysfs_lock);
+ sd->s_dentry = dentry;
++ spin_unlock(&sysfs_lock);
+ err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
+ if (!err) {
+ dentry->d_op = &sysfs_dentry_ops;
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/inode.c linux-source-2.6.18/fs/sysfs/inode.c
+--- linux-source-2.6.18.orig/fs/sysfs/inode.c 2007-11-07 15:44:57.000000000 -0700
++++ linux-source-2.6.18/fs/sysfs/inode.c 2007-11-07 15:40:19.000000000 -0700
+@@ -217,8 +217,22 @@ const unsigned char * sysfs_get_name(str
+ */
+ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
+ {
+- struct dentry * dentry = sd->s_dentry;
++ struct dentry *dentry = NULL;
+
++ /* We're not holding a reference to ->s_dentry dentry but the
++ * field will stay valid as long as sysfs_lock is held.
++ */
++ spin_lock(&sysfs_lock);
++ spin_lock(&dcache_lock);
++
++ /* dget dentry if it's still alive */
++ if (sd->s_dentry && sd->s_dentry->d_inode)
++ dentry = dget_locked(sd->s_dentry);
++
++ spin_unlock(&dcache_lock);
++ spin_unlock(&sysfs_lock);
++
++ /* drop dentry */
+ if (dentry) {
+ spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
+@@ -232,6 +246,8 @@ void sysfs_drop_dentry(struct sysfs_dire
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
+ }
++
++ dput(dentry);
+ }
+ }
+
+diff -urpN linux-source-2.6.18.orig/fs/sysfs/sysfs.h linux-source-2.6.18/fs/sysfs/sysfs.h
+--- linux-source-2.6.18.orig/fs/sysfs/sysfs.h 2006-09-19 21:42:06.000000000 -0600
++++ linux-source-2.6.18/fs/sysfs/sysfs.h 2007-11-07 15:38:57.000000000 -0700
+@@ -20,6 +20,7 @@ extern const unsigned char * sysfs_get_n
+ extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);
+ extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
+
++extern spinlock_t sysfs_lock;
+ extern struct rw_semaphore sysfs_rename_sem;
+ extern struct super_block * sysfs_sb;
+ extern const struct file_operations sysfs_dir_operations;
Added: dists/etch-security/linux-2.6/debian/patches/series/13etch5
==============================================================================
--- (empty file)
+++ dists/etch-security/linux-2.6/debian/patches/series/13etch5 Thu Nov 8 04:01:42 2007
@@ -0,0 +1,3 @@
++ bugfix/sysfs_readdir-NULL-deref-1.patch
++ bugfix/sysfs_readdir-NULL-deref-2.patch
++ bugfix/sysfs-fix-condition-check.patch
More information about the Kernel-svn-changes
mailing list