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 <[EMAIL PROTECTED]>  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 <[EMAIL PROTECTED]>
+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 <[EMAIL PROTECTED]>
+Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
+---
+
+Adjusted to apply to Debian's 2.6.18 by dann frazier <[EMAIL PROTECTED]>
+
+--- 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 <[EMAIL PROTECTED]>
+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 <[EMAIL PROTECTED]>
+Signed-off-by: Tejun Heo <[EMAIL PROTECTED]>
+Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <[EMAIL PROTECTED]>
+
+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 <[EMAIL PROTECTED]>
+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 <[EMAIL PROTECTED]>
+Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <[EMAIL PROTECTED]>
+
+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

_______________________________________________
Kernel-svn-changes mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/kernel-svn-changes

Reply via email to