r2284 - in trunk/kernel/source: kernel-source-2.6.10-2.6.10/debian kernel-source-2.6.10-2.6.10/debian/patches kernel-source-2.6.10-2.6.10/debian/patches/series kernel-source-2.6.8-2.6.8/debian kernel-source-2.6.8-2.6.8/debian/patches kernel-source-2.6.8-2.6.8/debian/patches/series kernel-source-2.6.9-2.6.9/debian kernel-source-2.6.9-2.6.9/debian/patches kernel-source-2.6.9-2.6.9/debian/patches/series

Andres Salomon dilinger-guest@costa.debian.org
Thu, 13 Jan 2005 07:47:09 +0100


Author: dilinger-guest
Date: 2005-01-13 07:47:07 +0100 (Thu, 13 Jan 2005)
New Revision: 2284

Added:
   trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/033-rlimit_memlock_check.dpatch
   trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/034-stack_resize_exploit.dpatch
   trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/035-do_brk_security_fixes-2.dpatch
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/033-rlimit_memlock_check.dpatch
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/034-stack_resize_exploit.dpatch
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/035-do_brk_security_fixes-2.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/033-rlimit_memlock_check.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/034-stack_resize_exploit.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/035-do_brk_security_fixes-2.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-6
Modified:
   trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/changelog
   trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/series/2.6.10-4
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog
Log:
  * [SECURITY] 033-rlimit_memlock_check.dpatch
    RLIMIT_MEMLOCK isn't checked properly, allowing for a DoS attack.
    See http://seclists.org/lists/fulldisclosure/2005/Jan/0270.html for
    more details.  This patch fixes it, and all reorganizes the stack resize
    stuff a bit (*sigh*) (Andres Salomon).

  * [SECURITY] 034-stack_resize_exploit.dpatch
    Fix exploitable race condition on SMP and HT systems where two
    threads attempt to expand the stack at the same time.  This is
    CAN-2005-0001 (happy new year!) (Andres Salomon).

  * [SECURITY] 035-do_brk_security_fixes-2.dpatch
    Further do_brk fixes; just to be safe, lock everywhere do_brk
    is used (Andres Salomon).



Modified: trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/changelog	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/changelog	2005-01-13 06:47:07 UTC (rev 2284)
@@ -27,6 +27,21 @@
 
   * Fix weird alpha IO failures due to typo. (Maximilian Attems)
 
+  * [SECURITY] 033-rlimit_memlock_check.dpatch
+    RLIMIT_MEMLOCK isn't checked properly, allowing for a DoS attack.
+    See http://seclists.org/lists/fulldisclosure/2005/Jan/0270.html for
+    more details.  This patch fixes it, and all reorganizes the stack resize
+    stuff a bit (*sigh*) (Andres Salomon).
+
+  * [SECURITY] 034-stack_resize_exploit.dpatch
+    Fix exploitable race condition on SMP and HT systems where two
+    threads attempt to expand the stack at the same time.  This is
+    CAN-2005-0001 (happy new year!) (Andres Salomon).
+
+  * [SECURITY] 035-do_brk_security_fixes-2.dpatch
+    Further do_brk fixes; just to be safe, lock everywhere do_brk
+    is used (Andres Salomon).
+
  -- Sven Luther <luther@debian.org>  Mon, 10 Jan 2005 18:06:29 +0100
 
 kernel-source-2.6.10 (2.6.10-3) unstable; urgency=low

Added: trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/033-rlimit_memlock_check.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,182 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Clean up stack growth checks and move them into a common function.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/10 11:23:42-08:00 torvalds@ppc970.osdl.org 
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+# mm/mmap.c
+#   2005/01/10 11:23:35-08:00 torvalds@ppc970.osdl.org +61 -44
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:21:10 -08:00
++++ b/mm/mmap.c	2005-01-12 20:21:10 -08:00
+@@ -1335,13 +1335,58 @@
+ 	return prev ? prev->vm_next : vma;
+ }
+ 
++/*
++ * Verify that the stack growth is acceptable and
++ * update accounting. This is shared with both the
++ * grow-up and grow-down cases.
++ */
++static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, unsigned long grow)
++{
++	struct mm_struct *mm = vma->vm_mm;
++	struct rlimit *rlim = current->signal->rlim;
++
++	/* address space limit tests */
++	rlim = current->signal->rlim;
++	if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT)
++		return -ENOMEM;
++
++	/* Stack limit test */
++	if (size > rlim[RLIMIT_STACK].rlim_cur)
++		return -ENOMEM;
++
++	/* mlock limit tests */
++	if (vma->vm_flags & VM_LOCKED) {
++		unsigned long locked;
++		unsigned long limit;
++		locked = mm->locked_vm + grow;
++		limit = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
++		if (locked > limit)
++			return -ENOMEM;
++	}
++
++	/*
++	 * Overcommit..  This must be the final test, as it will
++	 * update security statistics.
++	 */
++	if (security_vm_enough_memory(grow))
++		return -ENOMEM;
++
++	/* Ok, everything looks good - let it rip */
++	mm->total_vm += grow;
++	if (vma->vm_flags & VM_LOCKED)
++		mm->locked_vm += grow;
++	__vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow);
++	return 0;
++}
++
+ #ifdef CONFIG_STACK_GROWSUP
+ /*
+  * vma is the first one with address > vma->vm_end.  Have to extend vma.
+  */
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1361,28 +1406,14 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
++	size = address - vma->vm_start;
+ 	grow = (address - vma->vm_end) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (address - vma->vm_start > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
+-	}
+-	vma->vm_end = address;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
++	error = acct_stack_growth(vma, size, grow);
++	if (!error)
++		vma->vm_end = address;
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *
+@@ -1409,7 +1440,8 @@
+  */
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1425,29 +1457,16 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
++	size = vma->vm_end - address;
+ 	grow = (vma->vm_start - address) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (vma->vm_end - address > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
++	error = acct_stack_growth(vma, size, grow);
++	if (!error) {
++		vma->vm_start = address;
++		vma->vm_pgoff -= grow;
+ 	}
+-	vma->vm_start = address;
+-	vma->vm_pgoff -= grow;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *

Added: trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/034-stack_resize_exploit.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/034-stack_resize_exploit.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/034-stack_resize_exploit.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,101 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Handle two threads both trying to expand their stack simultaneously.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:09:20-08:00 torvalds@ppc970.osdl.org 
+#   Handle two threads both trying to expand their stack simultaneously.
+#   
+#   We had all the locking right, but we didn't check whether one of the
+#   threads now no longer needed to expand, so we could incorrectly _shrink_
+#   the stack in the other thread instead (not only causing segfaults, but
+#   since we didn't do a proper unmap, we'd possibly leak pages too).
+#   
+#   So re-check the need for expand after getting the lock.
+#   
+#   Noticed by Paul Starzetz.
+# 
+# mm/mmap.c
+#   2005/01/12 08:09:12-08:00 torvalds@ppc970.osdl.org +25 -13
+#   Handle two threads both trying to expand their stack simultaneously.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:22:12 -08:00
++++ b/mm/mmap.c	2005-01-12 20:22:12 -08:00
+@@ -1475,7 +1475,6 @@
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1495,12 +1494,19 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
+-	size = address - vma->vm_start;
+-	grow = (address - vma->vm_end) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error)
+-		vma->vm_end = address;
++	/* Somebody else might have raced and expanded it already */
++	if (address > vma->vm_end) {
++		unsigned long size, grow;
++
++		size = address - vma->vm_start;
++		grow = (address - vma->vm_end) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error)
++			vma->vm_end = address;
++	}
+ 	anon_vma_unlock(vma);
+ 	return error;
+ }
+@@ -1528,7 +1534,6 @@
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1544,13 +1549,20 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
+-	size = vma->vm_end - address;
+-	grow = (vma->vm_start - address) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error) {
+-		vma->vm_start = address;
+-		vma->vm_pgoff -= grow;
++	/* Somebody else might have raced and expanded it already */
++	if (address < vma->vm_start) {
++		unsigned long size, grow;
++
++		size = vma->vm_end - address;
++		grow = (vma->vm_start - address) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error) {
++			vma->vm_start = address;
++			vma->vm_pgoff -= grow;
++		}
+ 	}
+ 	anon_vma_unlock(vma);
+ 	return error;

Added: trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/035-do_brk_security_fixes-2.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,334 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: [PATCH] do_brk() needs mmap_sem write-locked
+## DP: Patch author: marcelo.tosatti@cyclades.com
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:12:09-08:00 marcelo.tosatti@cyclades.com 
+#   [PATCH] do_brk() needs mmap_sem write-locked
+#   
+#   It seems to be general consensus that its safer to require all do_brk() callers
+#   to grab mmap_sem, and have do_brk to warn otherwise. This is what the following
+#   patch does.
+#   
+#   Similar version has been changed to in v2.4.
+#   
+#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+# 
+# arch/mips/kernel/irixelf.c
+#   2005/01/11 17:35:36-08:00 marcelo.tosatti@cyclades.com +10 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/sparc64/kernel/binfmt_aout32.c
+#   2005/01/11 17:37:28-08:00 marcelo.tosatti@cyclades.com +12 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/x86_64/ia32/ia32_aout.c
+#   2005/01/11 17:34:26-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_aout.c
+#   2005/01/11 17:31:51-08:00 marcelo.tosatti@cyclades.com +14 -3
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_elf.c
+#   2005/01/11 18:07:01-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# mm/mmap.c
+#   2005/01/11 17:43:11-08:00 marcelo.tosatti@cyclades.com +6 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+diff -Nru a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
+--- a/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
++++ b/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
+@@ -127,7 +127,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ 
+@@ -375,7 +377,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(len, (last_bss - len));
++		up_write(&current->mm->mmap_sem);
+ 	}
+ 	kfree(elf_phdata);
+ 
+@@ -562,7 +566,9 @@
+ 	unsigned long v;
+ 	struct prda *pp;
+ 
++	down_write(&current->mm->mmap_sem);
+ 	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
++	up_write(&current->mm->mmap_sem);
+ 
+ 	if (v < 0)
+ 		return;
+@@ -852,8 +858,11 @@
+ 
+ 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+ 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+-	if (bss > len)
++	if (bss > len) {
++	  down_write(&current->mm->mmap_sem);
+ 	  do_brk(len, bss-len);
++	  up_write(&current->mm->mmap_sem);
++	}
+ 	kfree(elf_phdata);
+ 	return 0;
+ }
+diff -Nru a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
+--- a/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
++++ b/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
+@@ -49,7 +49,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ /*
+@@ -246,10 +248,14 @@
+ 	if (N_MAGIC(ex) == NMAGIC) {
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -257,8 +263,10 @@
+ 
+ 	if (N_MAGIC(ex) == OMAGIC) {
+ 		loff_t pos = fd_offset;
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+ 			ex.a_text+ex.a_data + PAGE_SIZE - 1);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text+ex.a_data, &pos);
+ 	} else {
+@@ -272,7 +280,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(0, ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 				  (char __user *)N_TXTADDR(ex),
+ 				  ex.a_text+ex.a_data, &pos);
+@@ -389,7 +399,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
+--- a/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
++++ b/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
+@@ -115,7 +115,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ #if CORE_DUMP
+@@ -325,7 +327,10 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ 
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
++
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -361,7 +366,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+ 			flush_icache_range((unsigned long) N_TXTADDR(ex),
+@@ -469,8 +476,9 @@
+ 			error_time = jiffies;
+ 		}
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+@@ -494,7 +502,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
+--- a/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
+@@ -50,7 +50,10 @@
+ 	start = PAGE_ALIGN(start);
+ 	end = PAGE_ALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -323,10 +326,14 @@
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
+ 		/* <AOL></AOL> */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -346,8 +353,9 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -382,7 +390,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 					(char __user *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+@@ -487,8 +497,9 @@
+ 			       file->f_dentry->d_name.name);
+ 			error_time = jiffies;
+ 		}
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char __user *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+--- a/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
+@@ -88,7 +88,10 @@
+ 	start = ELF_PAGEALIGN(start);
+ 	end = ELF_PAGEALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -409,7 +412,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > elf_bss) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(elf_bss, last_bss - elf_bss);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(error))
+ 			goto out_close;
+ 	}
+@@ -449,7 +454,9 @@
+ 		goto out;
+ 	}
+ 
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(0, text_data);
++	up_write(&current->mm->mmap_sem);
+ 	if (!interpreter->f_op || !interpreter->f_op->read)
+ 		goto out;
+ 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
+@@ -457,8 +464,11 @@
+ 	flush_icache_range((unsigned long)addr,
+ 	                   (unsigned long)addr + text_data);
+ 
++
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
+ 		interp_ex->a_bss);
++	up_write(&current->mm->mmap_sem);
+ 	elf_entry = interp_ex->a_entry;
+ 
+ out:
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:26:27 -08:00
++++ b/mm/mmap.c	2005-01-12 20:26:27 -08:00
+@@ -1903,6 +1903,12 @@
+ 	}
+ 
+ 	/*
++	 * mm->mmap_sem is required to protect against another thread
++	 * changing the mappings in case we sleep.
++	 */
++	WARN_ON(down_read_trylock(&mm->mmap_sem));
++
++	/*
+ 	 * Clear old maps.  this also does some error checking for us
+ 	 */
+  munmap_back:

Modified: trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/series/2.6.10-4
===================================================================
--- trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/series/2.6.10-4	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.10-2.6.10/debian/patches/series/2.6.10-4	2005-01-13 06:47:07 UTC (rev 2284)
@@ -13,3 +13,6 @@
 - modular-vesafb.dpatch
 + modular-vesafb-3.dpatch
 + alpha-io-typo.dpatch
++ 033-rlimit_memlock_check.dpatch
++ 034-stack_resize_exploit.dpatch
++ 035-do_brk_security_fixes-2.dpatch

Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2005-01-13 06:47:07 UTC (rev 2284)
@@ -5,6 +5,21 @@
 
   * Fix viewsvn url for patches in README.Debian as reported by
     Alexander E. Patrakov. (Christoph Hellwig) (closes: #288062).
+
+  * [SECURITY] 033-rlimit_memlock_check.dpatch
+    RLIMIT_MEMLOCK isn't checked properly, allowing for a DoS attack.
+    See http://seclists.org/lists/fulldisclosure/2005/Jan/0270.html for
+    more details.  This patch fixes it, and all reorganizes the stack resize
+    stuff a bit (*sigh*) (Andres Salomon).
+
+  * [SECURITY] 034-stack_resize_exploit.dpatch
+    Fix exploitable race condition on SMP and HT systems where two
+    threads attempt to expand the stack at the same time.  This is
+    CAN-2005-0001 (happy new year!) (Andres Salomon).
+
+  * [SECURITY] 035-do_brk_security_fixes-2.dpatch
+    Further do_brk fixes; just to be safe, lock everywhere do_brk
+    is used (Andres Salomon).
  
  -- Christoph Hellwig <hch@lst.de>  Sat, 08 Jan 2005 13:38:12 +0100
 

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/033-rlimit_memlock_check.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,182 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Clean up stack growth checks and move them into a common function.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/10 11:23:42-08:00 torvalds@ppc970.osdl.org 
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+# mm/mmap.c
+#   2005/01/10 11:23:35-08:00 torvalds@ppc970.osdl.org +61 -44
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:21:10 -08:00
++++ b/mm/mmap.c	2005-01-12 20:21:10 -08:00
+@@ -1335,13 +1335,58 @@
+ 	return prev ? prev->vm_next : vma;
+ }
+ 
++/*
++ * Verify that the stack growth is acceptable and
++ * update accounting. This is shared with both the
++ * grow-up and grow-down cases.
++ */
++static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, unsigned long grow)
++{
++	struct mm_struct *mm = vma->vm_mm;
++	struct rlimit *rlim = current->signal->rlim;
++
++	/* address space limit tests */
++	rlim = current->signal->rlim;
++	if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT)
++		return -ENOMEM;
++
++	/* Stack limit test */
++	if (size > rlim[RLIMIT_STACK].rlim_cur)
++		return -ENOMEM;
++
++	/* mlock limit tests */
++	if (vma->vm_flags & VM_LOCKED) {
++		unsigned long locked;
++		unsigned long limit;
++		locked = mm->locked_vm + grow;
++		limit = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
++		if (locked > limit)
++			return -ENOMEM;
++	}
++
++	/*
++	 * Overcommit..  This must be the final test, as it will
++	 * update security statistics.
++	 */
++	if (security_vm_enough_memory(grow))
++		return -ENOMEM;
++
++	/* Ok, everything looks good - let it rip */
++	mm->total_vm += grow;
++	if (vma->vm_flags & VM_LOCKED)
++		mm->locked_vm += grow;
++	__vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow);
++	return 0;
++}
++
+ #ifdef CONFIG_STACK_GROWSUP
+ /*
+  * vma is the first one with address > vma->vm_end.  Have to extend vma.
+  */
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1361,28 +1406,14 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
++	size = address - vma->vm_start;
+ 	grow = (address - vma->vm_end) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (address - vma->vm_start > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
+-	}
+-	vma->vm_end = address;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
++	error = acct_stack_growth(vma, size, grow);
++	if (!error)
++		vma->vm_end = address;
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *
+@@ -1409,7 +1440,8 @@
+  */
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1425,29 +1457,16 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
++	size = vma->vm_end - address;
+ 	grow = (vma->vm_start - address) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (vma->vm_end - address > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
++	error = acct_stack_growth(vma, size, grow);
++	if (!error) {
++		vma->vm_start = address;
++		vma->vm_pgoff -= grow;
+ 	}
+-	vma->vm_start = address;
+-	vma->vm_pgoff -= grow;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/034-stack_resize_exploit.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/034-stack_resize_exploit.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/034-stack_resize_exploit.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,101 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Handle two threads both trying to expand their stack simultaneously.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:09:20-08:00 torvalds@ppc970.osdl.org 
+#   Handle two threads both trying to expand their stack simultaneously.
+#   
+#   We had all the locking right, but we didn't check whether one of the
+#   threads now no longer needed to expand, so we could incorrectly _shrink_
+#   the stack in the other thread instead (not only causing segfaults, but
+#   since we didn't do a proper unmap, we'd possibly leak pages too).
+#   
+#   So re-check the need for expand after getting the lock.
+#   
+#   Noticed by Paul Starzetz.
+# 
+# mm/mmap.c
+#   2005/01/12 08:09:12-08:00 torvalds@ppc970.osdl.org +25 -13
+#   Handle two threads both trying to expand their stack simultaneously.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:22:12 -08:00
++++ b/mm/mmap.c	2005-01-12 20:22:12 -08:00
+@@ -1475,7 +1475,6 @@
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1495,12 +1494,19 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
+-	size = address - vma->vm_start;
+-	grow = (address - vma->vm_end) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error)
+-		vma->vm_end = address;
++	/* Somebody else might have raced and expanded it already */
++	if (address > vma->vm_end) {
++		unsigned long size, grow;
++
++		size = address - vma->vm_start;
++		grow = (address - vma->vm_end) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error)
++			vma->vm_end = address;
++	}
+ 	anon_vma_unlock(vma);
+ 	return error;
+ }
+@@ -1528,7 +1534,6 @@
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1544,13 +1549,20 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
+-	size = vma->vm_end - address;
+-	grow = (vma->vm_start - address) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error) {
+-		vma->vm_start = address;
+-		vma->vm_pgoff -= grow;
++	/* Somebody else might have raced and expanded it already */
++	if (address < vma->vm_start) {
++		unsigned long size, grow;
++
++		size = vma->vm_end - address;
++		grow = (vma->vm_start - address) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error) {
++			vma->vm_start = address;
++			vma->vm_pgoff -= grow;
++		}
+ 	}
+ 	anon_vma_unlock(vma);
+ 	return error;

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/035-do_brk_security_fixes-2.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,334 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: [PATCH] do_brk() needs mmap_sem write-locked
+## DP: Patch author: marcelo.tosatti@cyclades.com
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:12:09-08:00 marcelo.tosatti@cyclades.com 
+#   [PATCH] do_brk() needs mmap_sem write-locked
+#   
+#   It seems to be general consensus that its safer to require all do_brk() callers
+#   to grab mmap_sem, and have do_brk to warn otherwise. This is what the following
+#   patch does.
+#   
+#   Similar version has been changed to in v2.4.
+#   
+#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+# 
+# arch/mips/kernel/irixelf.c
+#   2005/01/11 17:35:36-08:00 marcelo.tosatti@cyclades.com +10 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/sparc64/kernel/binfmt_aout32.c
+#   2005/01/11 17:37:28-08:00 marcelo.tosatti@cyclades.com +12 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/x86_64/ia32/ia32_aout.c
+#   2005/01/11 17:34:26-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_aout.c
+#   2005/01/11 17:31:51-08:00 marcelo.tosatti@cyclades.com +14 -3
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_elf.c
+#   2005/01/11 18:07:01-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# mm/mmap.c
+#   2005/01/11 17:43:11-08:00 marcelo.tosatti@cyclades.com +6 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+diff -Nru a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
+--- a/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
++++ b/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
+@@ -127,7 +127,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ 
+@@ -375,7 +377,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(len, (last_bss - len));
++		up_write(&current->mm->mmap_sem);
+ 	}
+ 	kfree(elf_phdata);
+ 
+@@ -562,7 +566,9 @@
+ 	unsigned long v;
+ 	struct prda *pp;
+ 
++	down_write(&current->mm->mmap_sem);
+ 	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
++	up_write(&current->mm->mmap_sem);
+ 
+ 	if (v < 0)
+ 		return;
+@@ -852,8 +858,11 @@
+ 
+ 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+ 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+-	if (bss > len)
++	if (bss > len) {
++	  down_write(&current->mm->mmap_sem);
+ 	  do_brk(len, bss-len);
++	  up_write(&current->mm->mmap_sem);
++	}
+ 	kfree(elf_phdata);
+ 	return 0;
+ }
+diff -Nru a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
+--- a/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
++++ b/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
+@@ -49,7 +49,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ /*
+@@ -246,10 +248,14 @@
+ 	if (N_MAGIC(ex) == NMAGIC) {
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -257,8 +263,10 @@
+ 
+ 	if (N_MAGIC(ex) == OMAGIC) {
+ 		loff_t pos = fd_offset;
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+ 			ex.a_text+ex.a_data + PAGE_SIZE - 1);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text+ex.a_data, &pos);
+ 	} else {
+@@ -272,7 +280,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(0, ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 				  (char __user *)N_TXTADDR(ex),
+ 				  ex.a_text+ex.a_data, &pos);
+@@ -389,7 +399,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
+--- a/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
++++ b/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
+@@ -115,7 +115,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ #if CORE_DUMP
+@@ -325,7 +327,10 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ 
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
++
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -361,7 +366,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+ 			flush_icache_range((unsigned long) N_TXTADDR(ex),
+@@ -469,8 +476,9 @@
+ 			error_time = jiffies;
+ 		}
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+@@ -494,7 +502,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
+--- a/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
+@@ -50,7 +50,10 @@
+ 	start = PAGE_ALIGN(start);
+ 	end = PAGE_ALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -323,10 +326,14 @@
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
+ 		/* <AOL></AOL> */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -346,8 +353,9 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -382,7 +390,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 					(char __user *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+@@ -487,8 +497,9 @@
+ 			       file->f_dentry->d_name.name);
+ 			error_time = jiffies;
+ 		}
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char __user *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+--- a/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
+@@ -88,7 +88,10 @@
+ 	start = ELF_PAGEALIGN(start);
+ 	end = ELF_PAGEALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -409,7 +412,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > elf_bss) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(elf_bss, last_bss - elf_bss);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(error))
+ 			goto out_close;
+ 	}
+@@ -449,7 +454,9 @@
+ 		goto out;
+ 	}
+ 
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(0, text_data);
++	up_write(&current->mm->mmap_sem);
+ 	if (!interpreter->f_op || !interpreter->f_op->read)
+ 		goto out;
+ 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
+@@ -457,8 +464,11 @@
+ 	flush_icache_range((unsigned long)addr,
+ 	                   (unsigned long)addr + text_data);
+ 
++
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
+ 		interp_ex->a_bss);
++	up_write(&current->mm->mmap_sem);
+ 	elf_entry = interp_ex->a_entry;
+ 
+ out:
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:26:27 -08:00
++++ b/mm/mmap.c	2005-01-12 20:26:27 -08:00
+@@ -1903,6 +1903,12 @@
+ 	}
+ 
+ 	/*
++	 * mm->mmap_sem is required to protect against another thread
++	 * changing the mappings in case we sleep.
++	 */
++	WARN_ON(down_read_trylock(&mm->mmap_sem));
++
++	/*
+ 	 * Clear old maps.  this also does some error checking for us
+ 	 */
+  munmap_back:

Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13	2005-01-13 06:47:07 UTC (rev 2284)
@@ -1,3 +1,6 @@
 + scsi-blacklist-2.dpatch
 - smbfs-overflow-fixes.dpatch
 + smbfs-overflow-fixes-2.dpatch
++ 033-rlimit_memlock_check.dpatch
++ 034-stack_resize_exploit.dpatch
++ 035-do_brk_security_fixes-2.dpatch

Modified: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog	2005-01-13 06:47:07 UTC (rev 2284)
@@ -1,3 +1,22 @@
+kernel-source-2.6.9 (2.6.9-5) UNRELEASED; urgency=low
+ 
+  * [SECURITY] 033-rlimit_memlock_check.dpatch
+    RLIMIT_MEMLOCK isn't checked properly, allowing for a DoS attack.
+    See http://seclists.org/lists/fulldisclosure/2005/Jan/0270.html for
+    more details.  This patch fixes it, and all reorganizes the stack resize
+    stuff a bit (*sigh*) (Andres Salomon).
+
+  * [SECURITY] 034-stack_resize_exploit.dpatch
+    Fix exploitable race condition on SMP and HT systems where two
+    threads attempt to expand the stack at the same time.  This is
+    CAN-2005-0001 (happy new year!) (Andres Salomon).
+
+  * [SECURITY] 035-do_brk_security_fixes-2.dpatch
+    Further do_brk fixes; just to be safe, lock everywhere do_brk
+    is used (Andres Salomon).
+
+ -- Andres Salomon <dilinger@voxel.net>  Thu, 13 Jan 2005 01:50:48 -0500
+
 kernel-source-2.6.9 (2.6.9-5) unstable; urgency=low
 
   * [powerpc] Added a couple of powermac patches from Benjamin Herrenschmidt :

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/033-rlimit_memlock_check.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/033-rlimit_memlock_check.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,182 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Clean up stack growth checks and move them into a common function.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/10 11:23:42-08:00 torvalds@ppc970.osdl.org 
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+# mm/mmap.c
+#   2005/01/10 11:23:35-08:00 torvalds@ppc970.osdl.org +61 -44
+#   Clean up stack growth checks and move them into a common function.
+#   
+#   The grows-up and grows-down cases had all the same issues, but
+#   differered in the details. Additionlly, historical evolution of
+#   the tests had caused the result to be pretty unreadable with some
+#   rather long and complex conditionals.
+#   
+#   Fix it all up in a more readable helper function.
+#   
+#   This also adds the missing RLIMIT_MEMLOCK test.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:21:10 -08:00
++++ b/mm/mmap.c	2005-01-12 20:21:10 -08:00
+@@ -1335,13 +1335,58 @@
+ 	return prev ? prev->vm_next : vma;
+ }
+ 
++/*
++ * Verify that the stack growth is acceptable and
++ * update accounting. This is shared with both the
++ * grow-up and grow-down cases.
++ */
++static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, unsigned long grow)
++{
++	struct mm_struct *mm = vma->vm_mm;
++	struct rlimit *rlim = current->signal->rlim;
++
++	/* address space limit tests */
++	rlim = current->signal->rlim;
++	if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT)
++		return -ENOMEM;
++
++	/* Stack limit test */
++	if (size > rlim[RLIMIT_STACK].rlim_cur)
++		return -ENOMEM;
++
++	/* mlock limit tests */
++	if (vma->vm_flags & VM_LOCKED) {
++		unsigned long locked;
++		unsigned long limit;
++		locked = mm->locked_vm + grow;
++		limit = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
++		if (locked > limit)
++			return -ENOMEM;
++	}
++
++	/*
++	 * Overcommit..  This must be the final test, as it will
++	 * update security statistics.
++	 */
++	if (security_vm_enough_memory(grow))
++		return -ENOMEM;
++
++	/* Ok, everything looks good - let it rip */
++	mm->total_vm += grow;
++	if (vma->vm_flags & VM_LOCKED)
++		mm->locked_vm += grow;
++	__vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow);
++	return 0;
++}
++
+ #ifdef CONFIG_STACK_GROWSUP
+ /*
+  * vma is the first one with address > vma->vm_end.  Have to extend vma.
+  */
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1361,28 +1406,14 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
++	size = address - vma->vm_start;
+ 	grow = (address - vma->vm_end) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (address - vma->vm_start > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
+-	}
+-	vma->vm_end = address;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
++	error = acct_stack_growth(vma, size, grow);
++	if (!error)
++		vma->vm_end = address;
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *
+@@ -1409,7 +1440,8 @@
+  */
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+-	unsigned long grow;
++	int error;
++	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1425,29 +1457,16 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
++	size = vma->vm_end - address;
+ 	grow = (vma->vm_start - address) >> PAGE_SHIFT;
+ 
+-	/* Overcommit.. */
+-	if (security_vm_enough_memory(grow)) {
+-		anon_vma_unlock(vma);
+-		return -ENOMEM;
+-	}
+-	
+-	if (vma->vm_end - address > current->signal->rlim[RLIMIT_STACK].rlim_cur ||
+-			((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+-			current->signal->rlim[RLIMIT_AS].rlim_cur) {
+-		anon_vma_unlock(vma);
+-		vm_unacct_memory(grow);
+-		return -ENOMEM;
++	error = acct_stack_growth(vma, size, grow);
++	if (!error) {
++		vma->vm_start = address;
++		vma->vm_pgoff -= grow;
+ 	}
+-	vma->vm_start = address;
+-	vma->vm_pgoff -= grow;
+-	vma->vm_mm->total_vm += grow;
+-	if (vma->vm_flags & VM_LOCKED)
+-		vma->vm_mm->locked_vm += grow;
+-	__vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow);
+ 	anon_vma_unlock(vma);
+-	return 0;
++	return error;
+ }
+ 
+ struct vm_area_struct *

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/034-stack_resize_exploit.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/034-stack_resize_exploit.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/034-stack_resize_exploit.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,101 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Handle two threads both trying to expand their stack simultaneously.
+## DP: Patch author: torvalds@ppc970.osdl.org
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:09:20-08:00 torvalds@ppc970.osdl.org 
+#   Handle two threads both trying to expand their stack simultaneously.
+#   
+#   We had all the locking right, but we didn't check whether one of the
+#   threads now no longer needed to expand, so we could incorrectly _shrink_
+#   the stack in the other thread instead (not only causing segfaults, but
+#   since we didn't do a proper unmap, we'd possibly leak pages too).
+#   
+#   So re-check the need for expand after getting the lock.
+#   
+#   Noticed by Paul Starzetz.
+# 
+# mm/mmap.c
+#   2005/01/12 08:09:12-08:00 torvalds@ppc970.osdl.org +25 -13
+#   Handle two threads both trying to expand their stack simultaneously.
+# 
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:22:12 -08:00
++++ b/mm/mmap.c	2005-01-12 20:22:12 -08:00
+@@ -1475,7 +1475,6 @@
+ int expand_stack(struct vm_area_struct * vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	if (!(vma->vm_flags & VM_GROWSUP))
+ 		return -EFAULT;
+@@ -1495,12 +1494,19 @@
+ 	 */
+ 	address += 4 + PAGE_SIZE - 1;
+ 	address &= PAGE_MASK;
+-	size = address - vma->vm_start;
+-	grow = (address - vma->vm_end) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error)
+-		vma->vm_end = address;
++	/* Somebody else might have raced and expanded it already */
++	if (address > vma->vm_end) {
++		unsigned long size, grow;
++
++		size = address - vma->vm_start;
++		grow = (address - vma->vm_end) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error)
++			vma->vm_end = address;
++	}
+ 	anon_vma_unlock(vma);
+ 	return error;
+ }
+@@ -1528,7 +1534,6 @@
+ int expand_stack(struct vm_area_struct *vma, unsigned long address)
+ {
+ 	int error;
+-	unsigned long size, grow;
+ 
+ 	/*
+ 	 * We must make sure the anon_vma is allocated
+@@ -1544,13 +1549,20 @@
+ 	 * anon_vma lock to serialize against concurrent expand_stacks.
+ 	 */
+ 	address &= PAGE_MASK;
+-	size = vma->vm_end - address;
+-	grow = (vma->vm_start - address) >> PAGE_SHIFT;
++	error = 0;
+ 
+-	error = acct_stack_growth(vma, size, grow);
+-	if (!error) {
+-		vma->vm_start = address;
+-		vma->vm_pgoff -= grow;
++	/* Somebody else might have raced and expanded it already */
++	if (address < vma->vm_start) {
++		unsigned long size, grow;
++
++		size = vma->vm_end - address;
++		grow = (vma->vm_start - address) >> PAGE_SHIFT;
++
++		error = acct_stack_growth(vma, size, grow);
++		if (!error) {
++			vma->vm_start = address;
++			vma->vm_pgoff -= grow;
++		}
+ 	}
+ 	anon_vma_unlock(vma);
+ 	return error;

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/035-do_brk_security_fixes-2.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/035-do_brk_security_fixes-2.dpatch	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,334 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: [PATCH] do_brk() needs mmap_sem write-locked
+## DP: Patch author: marcelo.tosatti@cyclades.com
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2005/01/12 08:12:09-08:00 marcelo.tosatti@cyclades.com 
+#   [PATCH] do_brk() needs mmap_sem write-locked
+#   
+#   It seems to be general consensus that its safer to require all do_brk() callers
+#   to grab mmap_sem, and have do_brk to warn otherwise. This is what the following
+#   patch does.
+#   
+#   Similar version has been changed to in v2.4.
+#   
+#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+# 
+# arch/mips/kernel/irixelf.c
+#   2005/01/11 17:35:36-08:00 marcelo.tosatti@cyclades.com +10 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/sparc64/kernel/binfmt_aout32.c
+#   2005/01/11 17:37:28-08:00 marcelo.tosatti@cyclades.com +12 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+# arch/x86_64/ia32/ia32_aout.c
+#   2005/01/11 17:34:26-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_aout.c
+#   2005/01/11 17:31:51-08:00 marcelo.tosatti@cyclades.com +14 -3
+#   do_brk() needs mmap_sem write-locked
+# 
+# fs/binfmt_elf.c
+#   2005/01/11 18:07:01-08:00 marcelo.tosatti@cyclades.com +11 -1
+#   do_brk() needs mmap_sem write-locked
+# 
+# mm/mmap.c
+#   2005/01/11 17:43:11-08:00 marcelo.tosatti@cyclades.com +6 -0
+#   do_brk() needs mmap_sem write-locked
+# 
+diff -Nru a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
+--- a/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
++++ b/arch/mips/kernel/irixelf.c	2005-01-12 20:26:27 -08:00
+@@ -127,7 +127,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ 
+@@ -375,7 +377,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(len, (last_bss - len));
++		up_write(&current->mm->mmap_sem);
+ 	}
+ 	kfree(elf_phdata);
+ 
+@@ -562,7 +566,9 @@
+ 	unsigned long v;
+ 	struct prda *pp;
+ 
++	down_write(&current->mm->mmap_sem);
+ 	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
++	up_write(&current->mm->mmap_sem);
+ 
+ 	if (v < 0)
+ 		return;
+@@ -852,8 +858,11 @@
+ 
+ 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+ 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+-	if (bss > len)
++	if (bss > len) {
++	  down_write(&current->mm->mmap_sem);
+ 	  do_brk(len, bss-len);
++	  up_write(&current->mm->mmap_sem);
++	}
+ 	kfree(elf_phdata);
+ 	return 0;
+ }
+diff -Nru a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
+--- a/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
++++ b/arch/sparc64/kernel/binfmt_aout32.c	2005-01-12 20:26:27 -08:00
+@@ -49,7 +49,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ /*
+@@ -246,10 +248,14 @@
+ 	if (N_MAGIC(ex) == NMAGIC) {
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -257,8 +263,10 @@
+ 
+ 	if (N_MAGIC(ex) == OMAGIC) {
+ 		loff_t pos = fd_offset;
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+ 			ex.a_text+ex.a_data + PAGE_SIZE - 1);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex),
+ 			  ex.a_text+ex.a_data, &pos);
+ 	} else {
+@@ -272,7 +280,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(0, ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 				  (char __user *)N_TXTADDR(ex),
+ 				  ex.a_text+ex.a_data, &pos);
+@@ -389,7 +399,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
+--- a/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
++++ b/arch/x86_64/ia32/ia32_aout.c	2005-01-12 20:26:27 -08:00
+@@ -115,7 +115,9 @@
+ 	end = PAGE_ALIGN(end);
+ 	if (end <= start)
+ 		return;
++	down_write(&current->mm->mmap_sem);
+ 	do_brk(start, end - start);
++	up_write(&current->mm->mmap_sem);
+ }
+ 
+ #if CORE_DUMP
+@@ -325,7 +327,10 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ 
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
++
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -361,7 +366,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+ 			flush_icache_range((unsigned long) N_TXTADDR(ex),
+@@ -469,8 +476,9 @@
+ 			error_time = jiffies;
+ 		}
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+@@ -494,7 +502,9 @@
+ 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
+ 	bss = ex.a_text + ex.a_data + ex.a_bss;
+ 	if (bss > len) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(start_addr + len, bss - len);
++		up_write(&current->mm->mmap_sem);
+ 		retval = error;
+ 		if (error != start_addr + len)
+ 			goto out;
+diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
+--- a/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_aout.c	2005-01-12 20:26:27 -08:00
+@@ -50,7 +50,10 @@
+ 	start = PAGE_ALIGN(start);
+ 	end = PAGE_ALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -323,10 +326,14 @@
+ 		loff_t pos = fd_offset;
+ 		/* Fuck me plenty... */
+ 		/* <AOL></AOL> */
++		down_write(&current->mm->mmap_sem);	
+ 		error = do_brk(N_TXTADDR(ex), ex.a_text);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ 			  ex.a_text, &pos);
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(N_DATADDR(ex), ex.a_data);
++		up_write(&current->mm->mmap_sem);
+ 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
+ 			  ex.a_data, &pos);
+ 		goto beyond_if;
+@@ -346,8 +353,9 @@
+ 		pos = 32;
+ 		map_size = ex.a_text+ex.a_data;
+ #endif
+-
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(text_addr & PAGE_MASK, map_size);
++		up_write(&current->mm->mmap_sem);
+ 		if (error != (text_addr & PAGE_MASK)) {
+ 			send_sig(SIGKILL, current, 0);
+ 			return error;
+@@ -382,7 +390,9 @@
+ 
+ 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ 			loff_t pos = fd_offset;
++			down_write(&current->mm->mmap_sem);
+ 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
++			up_write(&current->mm->mmap_sem);
+ 			bprm->file->f_op->read(bprm->file,
+ 					(char __user *)N_TXTADDR(ex),
+ 					ex.a_text+ex.a_data, &pos);
+@@ -487,8 +497,9 @@
+ 			       file->f_dentry->d_name.name);
+ 			error_time = jiffies;
+ 		}
+-
++		down_write(&current->mm->mmap_sem);
+ 		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
++		up_write(&current->mm->mmap_sem);
+ 		
+ 		file->f_op->read(file, (char __user *)start_addr,
+ 			ex.a_text + ex.a_data, &pos);
+diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+--- a/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
++++ b/fs/binfmt_elf.c	2005-01-12 20:26:27 -08:00
+@@ -88,7 +88,10 @@
+ 	start = ELF_PAGEALIGN(start);
+ 	end = ELF_PAGEALIGN(end);
+ 	if (end > start) {
+-		unsigned long addr = do_brk(start, end - start);
++		unsigned long addr;
++		down_write(&current->mm->mmap_sem);
++		addr = do_brk(start, end - start);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(addr))
+ 			return addr;
+ 	}
+@@ -409,7 +412,9 @@
+ 
+ 	/* Map the last of the bss segment */
+ 	if (last_bss > elf_bss) {
++		down_write(&current->mm->mmap_sem);
+ 		error = do_brk(elf_bss, last_bss - elf_bss);
++		up_write(&current->mm->mmap_sem);
+ 		if (BAD_ADDR(error))
+ 			goto out_close;
+ 	}
+@@ -449,7 +454,9 @@
+ 		goto out;
+ 	}
+ 
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(0, text_data);
++	up_write(&current->mm->mmap_sem);
+ 	if (!interpreter->f_op || !interpreter->f_op->read)
+ 		goto out;
+ 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
+@@ -457,8 +464,11 @@
+ 	flush_icache_range((unsigned long)addr,
+ 	                   (unsigned long)addr + text_data);
+ 
++
++	down_write(&current->mm->mmap_sem);	
+ 	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
+ 		interp_ex->a_bss);
++	up_write(&current->mm->mmap_sem);
+ 	elf_entry = interp_ex->a_entry;
+ 
+ out:
+diff -Nru a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c	2005-01-12 20:26:27 -08:00
++++ b/mm/mmap.c	2005-01-12 20:26:27 -08:00
+@@ -1903,6 +1903,12 @@
+ 	}
+ 
+ 	/*
++	 * mm->mmap_sem is required to protect against another thread
++	 * changing the mappings in case we sleep.
++	 */
++	WARN_ON(down_read_trylock(&mm->mmap_sem));
++
++	/*
+ 	 * Clear old maps.  this also does some error checking for us
+ 	 */
+  munmap_back:

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-6
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-6	2005-01-12 18:54:32 UTC (rev 2283)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-6	2005-01-13 06:47:07 UTC (rev 2284)
@@ -0,0 +1,3 @@
++ 033-rlimit_memlock_check.dpatch
++ 034-stack_resize_exploit.dpatch
++ 035-do_brk_security_fixes-2.dpatch