[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