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

