[kernel] r15652 - in dists/lenny-security/linux-2.6/debian: . patches/bugfix/all patches/bugfix/powerpc patches/series

Dann Frazier dannf at alioth.debian.org
Mon May 10 05:21:33 UTC 2010


Author: dannf
Date: Mon May 10 05:21:29 2010
New Revision: 15652

Log:
KEYS: find_keyring_by_name() can gain access to a freed keyring
(CVE-2010-1437)

Added:
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/keys-find_keyring_by_name-can-gain-access-to-a-freed-keyring.patch
   dists/lenny-security/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch
      - copied unchanged from r15639, dists/sid/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch
Modified:
   dists/lenny-security/linux-2.6/debian/changelog
   dists/lenny-security/linux-2.6/debian/patches/series/22lenny1

Modified: dists/lenny-security/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny-security/linux-2.6/debian/changelog	Sun May  9 16:50:27 2010	(r15651)
+++ dists/lenny-security/linux-2.6/debian/changelog	Mon May 10 05:21:29 2010	(r15652)
@@ -13,6 +13,8 @@
   * sctp: Fix skb_over_panic resulting from multiple invalid parameter
     errors (CVE-2010-1173)
   * sparc64: Fix sun4u execute bit check in TSB I-TLB load (CVE-2010-1451)
+  * KEYS: find_keyring_by_name() can gain access to a freed keyring
+    (CVE-2010-1437)
 
   [ Ben Hutchings ]
   * [x86] KVM: disable paravirt mmu reporting (Closes: #573071) (regressed

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/keys-find_keyring_by_name-can-gain-access-to-a-freed-keyring.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/keys-find_keyring_by_name-can-gain-access-to-a-freed-keyring.patch	Mon May 10 05:21:29 2010	(r15652)
@@ -0,0 +1,183 @@
+commit 697efd52b4c5374c2133f5fe86a354f1b163a22d
+Author: Toshiyuki Okajima <toshi.okajima at jp.fujitsu.com>
+Date:   Fri Apr 30 14:32:13 2010 +0100
+
+    KEYS: find_keyring_by_name() can gain access to a freed keyring
+    
+    find_keyring_by_name() can gain access to a keyring that has had its reference
+    count reduced to zero, and is thus ready to be freed.  This then allows the
+    dead keyring to be brought back into use whilst it is being destroyed.
+    
+    The following timeline illustrates the process:
+    
+    |(cleaner)                           (user)
+    |
+    | free_user(user)                    sys_keyctl()
+    |  |                                  |
+    |  key_put(user->session_keyring)     keyctl_get_keyring_ID()
+    |  ||	//=> keyring->usage = 0        |
+    |  |schedule_work(&key_cleanup_task)   lookup_user_key()
+    |  ||                                   |
+    |  kmem_cache_free(,user)               |
+    |  .                                    |[KEY_SPEC_USER_KEYRING]
+    |  .                                    install_user_keyrings()
+    |  .                                    ||
+    | key_cleanup() [<= worker_thread()]    ||
+    |  |                                    ||
+    |  [spin_lock(&key_serial_lock)]        |[mutex_lock(&key_user_keyr..mutex)]
+    |  |                                    ||
+    |  atomic_read() == 0                   ||
+    |  |{ rb_ease(&key->serial_node,) }     ||
+    |  |                                    ||
+    |  [spin_unlock(&key_serial_lock)]      |find_keyring_by_name()
+    |  |                                    |||
+    |  keyring_destroy(keyring)             ||[read_lock(&keyring_name_lock)]
+    |  ||                                   |||
+    |  |[write_lock(&keyring_name_lock)]    ||atomic_inc(&keyring->usage)
+    |  |.                                   ||| *** GET freeing keyring ***
+    |  |.                                   ||[read_unlock(&keyring_name_lock)]
+    |  ||                                   ||
+    |  |list_del()                          |[mutex_unlock(&key_user_k..mutex)]
+    |  ||                                   |
+    |  |[write_unlock(&keyring_name_lock)]  ** INVALID keyring is returned **
+    |  |                                    .
+    |  kmem_cache_free(,keyring)            .
+    |                                       .
+    |                                       atomic_dec(&keyring->usage)
+    v                                         *** DESTROYED ***
+    TIME
+    
+    If CONFIG_SLUB_DEBUG=y then we may see the following message generated:
+    
+    	=============================================================================
+    	BUG key_jar: Poison overwritten
+    	-----------------------------------------------------------------------------
+    
+    	INFO: 0xffff880197a7e200-0xffff880197a7e200. First byte 0x6a instead of 0x6b
+    	INFO: Allocated in key_alloc+0x10b/0x35f age=25 cpu=1 pid=5086
+    	INFO: Freed in key_cleanup+0xd0/0xd5 age=12 cpu=1 pid=10
+    	INFO: Slab 0xffffea000592cb90 objects=16 used=2 fp=0xffff880197a7e200 flags=0x200000000000c3
+    	INFO: Object 0xffff880197a7e200 @offset=512 fp=0xffff880197a7e300
+    
+    	Bytes b4 0xffff880197a7e1f0:  5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
+    	  Object 0xffff880197a7e200:  6a 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b jkkkkkkkkkkkkkkk
+    
+    Alternatively, we may see a system panic happen, such as:
+    
+    	BUG: unable to handle kernel NULL pointer dereference at 0000000000000001
+    	IP: [<ffffffff810e61a3>] kmem_cache_alloc+0x5b/0xe9
+    	PGD 6b2b4067 PUD 6a80d067 PMD 0
+    	Oops: 0000 [#1] SMP
+    	last sysfs file: /sys/kernel/kexec_crash_loaded
+    	CPU 1
+    	...
+    	Pid: 31245, comm: su Not tainted 2.6.34-rc5-nofixed-nodebug #2 D2089/PRIMERGY
+    	RIP: 0010:[<ffffffff810e61a3>]  [<ffffffff810e61a3>] kmem_cache_alloc+0x5b/0xe9
+    	RSP: 0018:ffff88006af3bd98  EFLAGS: 00010002
+    	RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffff88007d19900b
+    	RDX: 0000000100000000 RSI: 00000000000080d0 RDI: ffffffff81828430
+    	RBP: ffffffff81828430 R08: ffff88000a293750 R09: 0000000000000000
+    	R10: 0000000000000001 R11: 0000000000100000 R12: 00000000000080d0
+    	R13: 00000000000080d0 R14: 0000000000000296 R15: ffffffff810f20ce
+    	FS:  00007f97116bc700(0000) GS:ffff88000a280000(0000) knlGS:0000000000000000
+    	CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+    	CR2: 0000000000000001 CR3: 000000006a91c000 CR4: 00000000000006e0
+    	DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+    	DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
+    	Process su (pid: 31245, threadinfo ffff88006af3a000, task ffff8800374414c0)
+    	Stack:
+    	 0000000512e0958e 0000000000008000 ffff880037f8d180 0000000000000001
+    	 0000000000000000 0000000000008001 ffff88007d199000 ffffffff810f20ce
+    	 0000000000008000 ffff88006af3be48 0000000000000024 ffffffff810face3
+    	Call Trace:
+    	 [<ffffffff810f20ce>] ? get_empty_filp+0x70/0x12f
+    	 [<ffffffff810face3>] ? do_filp_open+0x145/0x590
+    	 [<ffffffff810ce208>] ? tlb_finish_mmu+0x2a/0x33
+    	 [<ffffffff810ce43c>] ? unmap_region+0xd3/0xe2
+    	 [<ffffffff810e4393>] ? virt_to_head_page+0x9/0x2d
+    	 [<ffffffff81103916>] ? alloc_fd+0x69/0x10e
+    	 [<ffffffff810ef4ed>] ? do_sys_open+0x56/0xfc
+    	 [<ffffffff81008a02>] ? system_call_fastpath+0x16/0x1b
+    	Code: 0f 1f 44 00 00 49 89 c6 fa 66 0f 1f 44 00 00 65 4c 8b 04 25 60 e8 00 00 48 8b 45 00 49 01 c0 49 8b 18 48 85 db 74 0d 48 63 45 18 <48> 8b 04 03 49 89 00 eb 14 4c 89 f9 83 ca ff 44 89 e6 48 89 ef
+    	RIP  [<ffffffff810e61a3>] kmem_cache_alloc+0x5b/0xe9
+    
+    This problem is that find_keyring_by_name does not confirm that the keyring is
+    valid before accepting it.
+    
+    Skipping keyrings that have been reduced to a zero count seems the way to go.
+    To this end, use atomic_inc_not_zero() to increment the usage count and skip
+    the candidate keyring if that returns false.
+    
+    The following script _may_ cause the bug to happen, but there's no guarantee
+    as the window of opportunity is small:
+    
+    	#!/bin/sh
+    	LOOP=100000
+    	USER=dummy_user
+    	/bin/su -c "exit;" $USER || { /usr/sbin/adduser -m $USER; add=1; }
+    	for ((i=0; i<LOOP; i++))
+    	do
+    		/bin/su -c "echo '$i' > /dev/null" $USER
+    	done
+    	(( add == 1 )) && /usr/sbin/userdel -r $USER
+    	exit
+    
+    Note that the nominated user must not be in use.
+    
+    An alternative way of testing this may be:
+    
+    	for ((i=0; i<100000; i++))
+    	do
+    		keyctl session foo /bin/true || break
+    	done >&/dev/null
+    
+    as that uses a keyring named "foo" rather than relying on the user and
+    user-session named keyrings.
+    
+    Reported-by: Toshiyuki Okajima <toshi.okajima at jp.fujitsu.com>
+    Signed-off-by: David Howells <dhowells at redhat.com>
+    Tested-by: Toshiyuki Okajima <toshi.okajima at jp.fujitsu.com>
+    Acked-by: Serge Hallyn <serue at us.ibm.com>
+    Signed-off-by: James Morris <jmorris at namei.org>
+
+diff --git a/security/keys/keyring.c b/security/keys/keyring.c
+index a9ab8af..594660f 100644
+--- a/security/keys/keyring.c
++++ b/security/keys/keyring.c
+@@ -523,9 +523,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
+ 	struct key *keyring;
+ 	int bucket;
+ 
+-	keyring = ERR_PTR(-EINVAL);
+ 	if (!name)
+-		goto error;
++		return ERR_PTR(-EINVAL);
+ 
+ 	bucket = keyring_hash(name);
+ 
+@@ -549,17 +548,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
+ 					   KEY_SEARCH) < 0)
+ 				continue;
+ 
+-			/* we've got a match */
+-			atomic_inc(&keyring->usage);
+-			read_unlock(&keyring_name_lock);
+-			goto error;
++			/* we've got a match but we might end up racing with
++			 * key_cleanup() if the keyring is currently 'dead'
++			 * (ie. it has a zero usage count) */
++			if (!atomic_inc_not_zero(&keyring->usage))
++				continue;
++			goto out;
+ 		}
+ 	}
+ 
+-	read_unlock(&keyring_name_lock);
+ 	keyring = ERR_PTR(-ENOKEY);
+-
+- error:
++out:
++	read_unlock(&keyring_name_lock);
+ 	return keyring;
+ 
+ } /* end find_keyring_by_name() */

Copied: dists/lenny-security/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch (from r15639, dists/sid/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch	Mon May 10 05:21:29 2010	(r15652, copy of r15639, dists/sid/linux-2.6/debian/patches/bugfix/powerpc/kgdb-dont-needlessly-skip-PAGE_USER-test-for-Fsl-booke.patch)
@@ -0,0 +1,42 @@
+commit 56151e753468e34aeb322af4b0309ab727c97d2e
+Author: Wufei <fei.wu at windriver.com>
+Date:   Wed Apr 28 17:42:32 2010 -0400
+
+    kgdb: don't needlessly skip PAGE_USER test for Fsl booke
+    
+    The bypassing of this test is a leftover from 2.4 vintage
+    kernels, and is no longer appropriate, or even used by KGDB.
+    Currently KGDB uses probe_kernel_write() for all access to
+    memory via the KGDB core, so it can simply be deleted.
+    
+    This fixes CVE-2010-1446.
+    
+    CC: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+    CC: Paul Mackerras <paulus at samba.org>
+    CC: Kumar Gala <galak at kernel.crashing.org>
+    Signed-off-by: Wufei <fei.wu at windriver.com>
+    Signed-off-by: Jason Wessel <jason.wessel at windriver.com>
+
+
+Adjusted to apply to Debian's 2.6.32 by dann frazier <dannf at debian.org>
+
+
+diff -urpN a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
+--- a/arch/powerpc/mm/fsl_booke_mmu.c	2009-12-02 20:51:21.000000000 -0700
++++ b/arch/powerpc/mm/fsl_booke_mmu.c	2010-04-30 00:49:04.000000000 -0600
+@@ -131,15 +131,10 @@ void settlbcam(int index, unsigned long
+ 	TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR;
+ 	TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0);
+ 
+-#ifndef CONFIG_KGDB /* want user access for breakpoints */
+ 	if (flags & _PAGE_USER) {
+ 	   TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
+ 	   TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
+ 	}
+-#else
+-	TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
+-	TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
+-#endif
+ 
+ 	tlbcam_addrs[index].start = virt;
+ 	tlbcam_addrs[index].limit = virt + size - 1;

Modified: dists/lenny-security/linux-2.6/debian/patches/series/22lenny1
==============================================================================
--- dists/lenny-security/linux-2.6/debian/patches/series/22lenny1	Sun May  9 16:50:27 2010	(r15651)
+++ dists/lenny-security/linux-2.6/debian/patches/series/22lenny1	Mon May 10 05:21:29 2010	(r15652)
@@ -12,3 +12,4 @@
 + bugfix/all/tipc-fix-oops-on-send-prior-to-entering-networked-mode.patch
 + bugfix/all/sctp-fix-skb_over_panic-resulting-from-multiple-invalid-parameter-errors.patch
 + bugfix/sparc/fix-sun4u-execute-bit-check-in-TSB-I-ITLB-load.patch
++ bugfix/all/keys-find_keyring_by_name-can-gain-access-to-a-freed-keyring.patch



More information about the Kernel-svn-changes mailing list