summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch')
-rw-r--r--trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch112
1 files changed, 112 insertions, 0 deletions
diff --git a/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch b/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch
new file mode 100644
index 0000000..c13fd1b
--- /dev/null
+++ b/trunk/2.6.18/30048_sysfs_readdir-NULL-deref-1.patch
@@ -0,0 +1,112 @@
+From: Eric Sandeen <sandeen@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@redhat.com>
+Signed-off-by: Tejun Heo <htejun@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <dannf@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;