[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