[kernel] r4839 -
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series
patch-tracking
Dann Frazier
dannf at costa.debian.org
Fri Nov 18 18:08:05 UTC 2005
Author: dannf
Date: Fri Nov 18 18:08:04 2005
New Revision: 4839
Added:
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/196_sysctl-unregistration-oops.diff
Modified:
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-10sarge2
patch-tracking/cve-2005-2709-sysctl-unregistration-oops.patch
Log:
* 196_sysctl-unregistration-oops.patch
[SECURITY] Fix a potential local root exploit in the
/proc/sys/net/ipv4/conf interface. See CVE-2005-2709
Modified: dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
==============================================================================
--- dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog (original)
+++ dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog Fri Nov 18 18:08:04 2005
@@ -40,7 +40,12 @@
* 195_net-ipv6-udp_v6_get_port-loop.diff
[SECURITY] Fix infinite loop in udp_v6_get_port(). See CVE-2005-2973
- -- Simon Horman <horms at debian.org> Mon, 31 Oct 2005 18:44:52 +0900
+ * 196_sysctl-unregistration-oops.patch
+ [SECURITY] Fix a potential local root exploit in the
+ /proc/sys/net/ipv4/conf interface. See CVE-2005-2709
+
+
+ -- dann frazier <dannf at debian.org> Fri, 18 Nov 2005 11:04:04 -0700
kernel-source-2.4.27 (2.4.27-10sarge1) stable-security; urgency=high
Added: dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/196_sysctl-unregistration-oops.diff
==============================================================================
--- (empty file)
+++ dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/196_sysctl-unregistration-oops.diff Fri Nov 18 18:08:04 2005
@@ -0,0 +1,279 @@
+diff -urN kernel-source-2.4.27-2.4.27.orig/include/linux/proc_fs.h kernel-source-2.4.27-2.4.27/include/linux/proc_fs.h
+--- kernel-source-2.4.27-2.4.27.orig/include/linux/proc_fs.h 2005-11-18 10:48:28.000000000 -0700
++++ kernel-source-2.4.27-2.4.27/include/linux/proc_fs.h 2005-11-18 10:50:44.000000000 -0700
+@@ -70,6 +70,7 @@
+ atomic_t count; /* use count */
+ int deleted; /* delete flag */
+ kdev_t rdev;
++ void *set;
+ };
+
+ #define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff)
+diff -urN kernel-source-2.4.27-2.4.27.orig/include/linux/sysctl.h kernel-source-2.4.27-2.4.27/include/linux/sysctl.h
+--- kernel-source-2.4.27-2.4.27.orig/include/linux/sysctl.h 2005-11-18 10:48:29.000000000 -0700
++++ kernel-source-2.4.27-2.4.27/include/linux/sysctl.h 2005-11-18 10:50:44.000000000 -0700
+@@ -29,6 +29,7 @@
+ #include <linux/list.h>
+
+ struct file;
++struct completion;
+
+ #define CTL_MAXNAME 10
+
+@@ -833,6 +834,8 @@
+ {
+ ctl_table *ctl_table;
+ struct list_head ctl_entry;
++ int used;
++ struct completion *unregistering;
+ };
+
+ struct ctl_table_header * register_sysctl_table(ctl_table * table,
+diff -urN kernel-source-2.4.27-2.4.27.orig/kernel/sysctl.c kernel-source-2.4.27-2.4.27/kernel/sysctl.c
+--- kernel-source-2.4.27-2.4.27.orig/kernel/sysctl.c 2004-08-07 17:26:06.000000000 -0600
++++ kernel-source-2.4.27-2.4.27/kernel/sysctl.c 2005-11-18 10:50:44.000000000 -0700
+@@ -147,7 +147,7 @@
+
+ extern struct proc_dir_entry *proc_sys_root;
+
+-static void register_proc_table(ctl_table *, struct proc_dir_entry *);
++static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
+ static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
+ #endif
+
+@@ -358,10 +358,51 @@
+
+ extern void init_irq_proc (void);
+
++static spinlock_t sysctl_lock = SPIN_LOCK_UNLOCKED;
++
++/* called under sysctl_lock */
++static int use_table(struct ctl_table_header *p)
++{
++ if (unlikely(p->unregistering != NULL))
++ return 0;
++ p->used++;
++ return 1;
++}
++
++/* called under sysctl_lock */
++static void unuse_table(struct ctl_table_header *p)
++{
++ if (!--p->used)
++ if (unlikely(p->unregistering != NULL))
++ complete(p->unregistering);
++}
++
++/* called under sysctl_lock, will reacquire if has to wait */
++static void start_unregistering(struct ctl_table_header *p)
++{
++ /*
++ * if p->used is 0, nobody will ever touch that entry again;
++ * we'll eliminate all paths to it before dropping sysctl_lock
++ */
++ if (unlikely(p->used)) {
++ struct completion wait;
++ init_completion(&wait);
++ p->unregistering = &wait;
++ spin_unlock(&sysctl_lock);
++ wait_for_completion(&wait);
++ spin_lock(&sysctl_lock);
++ }
++ /*
++ * do not remove from the list until nobody holds it; walking the
++ * list in do_sysctl() relies on that.
++ */
++ list_del_init(&p->ctl_entry);
++}
++
+ void __init sysctl_init(void)
+ {
+ #ifdef CONFIG_PROC_FS
+- register_proc_table(root_table, proc_sys_root);
++ register_proc_table(root_table, proc_sys_root, &root_table_header);
+ init_irq_proc();
+ #endif
+ }
+@@ -370,6 +411,7 @@
+ void *newval, size_t newlen)
+ {
+ struct list_head *tmp;
++ int error = -ENOTDIR;
+
+ if (nlen <= 0 || nlen >= CTL_MAXNAME)
+ return -ENOTDIR;
+@@ -378,21 +420,31 @@
+ if (!oldlenp || get_user(old_len, oldlenp))
+ return -EFAULT;
+ }
++ spin_lock(&sysctl_lock);
+ tmp = &root_table_header.ctl_entry;
+ do {
+ struct ctl_table_header *head =
+ list_entry(tmp, struct ctl_table_header, ctl_entry);
+ void *context = NULL;
+- int error = parse_table(name, nlen, oldval, oldlenp,
++
++ if (!use_table(head))
++ continue;
++
++ spin_unlock(&sysctl_lock);
++
++ error = parse_table(name, nlen, oldval, oldlenp,
+ newval, newlen, head->ctl_table,
+ &context);
+ if (context)
+ kfree(context);
++
++ spin_lock(&sysctl_lock);
++ unuse_table(head);
+ if (error != -ENOTDIR)
+- return error;
+- tmp = tmp->next;
+- } while (tmp != &root_table_header.ctl_entry);
+- return -ENOTDIR;
++ break;
++ } while ((tmp = tmp->next) != &root_table_header.ctl_entry);
++ spin_unlock(&sysctl_lock);
++ return error;
+ }
+
+ extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
+@@ -599,12 +651,16 @@
+ return NULL;
+ tmp->ctl_table = table;
+ INIT_LIST_HEAD(&tmp->ctl_entry);
++ tmp->used = 0;
++ tmp->unregistering = NULL;
++ spin_lock(&sysctl_lock);
+ if (insert_at_head)
+ list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
+ else
+ list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
++ spin_unlock(&sysctl_lock);
+ #ifdef CONFIG_PROC_FS
+- register_proc_table(table, proc_sys_root);
++ register_proc_table(table, proc_sys_root, tmp);
+ #endif
+ return tmp;
+ }
+@@ -618,10 +674,12 @@
+ */
+ void unregister_sysctl_table(struct ctl_table_header * header)
+ {
+- list_del(&header->ctl_entry);
++ spin_lock(&sysctl_lock);
++ start_unregistering(header);
+ #ifdef CONFIG_PROC_FS
+ unregister_proc_table(header->ctl_table, proc_sys_root);
+ #endif
++ spin_unlock(&sysctl_lock);
+ kfree(header);
+ }
+
+@@ -632,7 +690,7 @@
+ #ifdef CONFIG_PROC_FS
+
+ /* Scan the sysctl entries in table and add them all into /proc */
+-static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
++static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
+ {
+ struct proc_dir_entry *de;
+ int len;
+@@ -668,6 +726,7 @@
+ de = create_proc_entry(table->procname, mode, root);
+ if (!de)
+ continue;
++ de->set = set;
+ de->data = (void *) table;
+ if (table->proc_handler) {
+ de->proc_fops = &proc_sys_file_operations;
+@@ -676,7 +735,7 @@
+ }
+ table->de = de;
+ if (de->mode & S_IFDIR)
+- register_proc_table(table->child, de);
++ register_proc_table(table->child, de, set);
+ }
+ }
+
+@@ -701,6 +760,13 @@
+ continue;
+ }
+
++ /*
++ * In any case, mark the entry as goner; we'll keep it
++ * around if it's busy, but we'll know to do nothing with
++ * its fields. We are under sysctl_lock here.
++ */
++ de->data = NULL;
++
+ /* Don't unregister proc entries that are still being used.. */
+ if (atomic_read(&de->count))
+ continue;
+@@ -714,31 +780,44 @@
+ size_t count, loff_t *ppos)
+ {
+ int op;
+- struct proc_dir_entry *de;
++ struct proc_dir_entry *de =
++ (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
+ struct ctl_table *table;
+ size_t res;
+- ssize_t error;
+-
+- de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
+- if (!de || !de->data)
+- return -ENOTDIR;
+- table = (struct ctl_table *) de->data;
+- if (!table || !table->proc_handler)
+- return -ENOTDIR;
+- op = (write ? 002 : 004);
+- if (ctl_perm(table, op))
+- return -EPERM;
+-
+- res = count;
++ ssize_t error = -ENOTDIR;
+
+- /*
+- * FIXME: we need to pass on ppos to the handler.
+- */
++ spin_lock(&sysctl_lock);
++ if (de && de->data && use_table(de->set)) {
++ /*
++ * at that point we know that sysctl was not unregistered
++ * and won't be until we finish
++ */
++ spin_unlock(&sysctl_lock);
++ table = (struct ctl_table *) de->data;
++ if (!table || !table->proc_handler)
++ goto out;
++ error = -EPERM;
++ op = (write ? 002 : 004);
++ if (ctl_perm(table, op))
++ goto out;
++
++ /* careful: calling conventions are nasty here */
++ res = count;
+
+- error = (*table->proc_handler) (table, write, file, buf, &res);
+- if (error)
+- return error;
+- return res;
++ /*
++ * FIXME: we need to pass on ppos to the handler.
++ */
++
++ error = (*table->proc_handler)(table, write, file,
++ buf, &res);
++ if (!error)
++ error = res;
++ out:
++ spin_lock(&sysctl_lock);
++ unuse_table(de->set);
++ }
++ spin_unlock(&sysctl_lock);
++ return error;
+ }
+
+ static ssize_t proc_readsys(struct file * file, char * buf,
Modified: dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-10sarge2
==============================================================================
--- dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-10sarge2 (original)
+++ dists/sarge-security/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-10sarge2 Fri Nov 18 18:08:04 2005
@@ -4,3 +4,4 @@
+ 192_orinoco-info-leak.diff
+ 194_xfs-inode-race.diff
+ 195_net-ipv6-udp_v6_get_port-loop.diff
++ 196_sysctl-unregistration-oops.diff
Modified: patch-tracking/cve-2005-2709-sysctl-unregistration-oops.patch
==============================================================================
--- patch-tracking/cve-2005-2709-sysctl-unregistration-oops.patch (original)
+++ patch-tracking/cve-2005-2709-sysctl-unregistration-oops.patch Fri Nov 18 18:08:04 2005
@@ -11,12 +11,15 @@
you'll get it called as ->proc_handler() in kernel mode.
Notes:
CVE is reserved, so we can't take the description from there yet
+ .
+ dannf> arch/s390/appldata/appldata_base.c doesn't exist in 2.4, so I dropped
+ dannf> that hunk in my backport
Bug:
upstream: pending (2.6.14.1)
2.6.13: needed
2.6.12:
-2.6.8-sarge-security: pending (2.6.8-16sarge2)
-2.4.27-sarge-security:
+2.6.8-sarge-security: pending (2.6.8-16sarge2) [sysctl-unregistration-oops.dpatch]
+2.4.27-sarge-security: pending (2.4.27-10sarge2) [196_sysctl-unregistration-oops.patch]
2.4.27:
2.6.14:
2.6.8:
More information about the Kernel-svn-changes
mailing list