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

Dann Frazier dannf at alioth.debian.org
Mon Jan 17 07:13:17 UTC 2011


Author: dannf
Date: Mon Jan 17 07:12:59 2011
New Revision: 16823

Log:
exec: make argv/envp memory visible to oom-killer (CVE-2010-4243)

Added:
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch
   dists/lenny-security/linux-2.6/debian/patches/debian/exec-Get-rid-of-linux_binprm-vma_pages.patch
Modified:
   dists/lenny-security/linux-2.6/debian/changelog
   dists/lenny-security/linux-2.6/debian/patches/series/26lenny2

Modified: dists/lenny-security/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny-security/linux-2.6/debian/changelog	Sun Jan 16 22:35:15 2011	(r16822)
+++ dists/lenny-security/linux-2.6/debian/changelog	Mon Jan 17 07:12:59 2011	(r16823)
@@ -11,6 +11,7 @@
     (CVE-2010-4248)
   * KVM: VMX: fix vmx null pointer dereference on debug register access
     (CVE-2010-0435)
+  * exec: make argv/envp memory visible to oom-killer (CVE-2010-4243)
 
   [ Moritz Muehlenhoff ]
   * blkback/blktap/netback: Fix CVE-2010-3699 	

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch	Mon Jan 17 07:12:59 2011	(r16823)
@@ -0,0 +1,148 @@
+commit 56b0121a596775ab05388211fcfeafc3b7c77ae3
+Author: dann frazier <dann.frazier at canonical.com>
+Date:   Wed Jan 12 22:28:23 2011 -0700
+
+    From 114279be2120a916e8a04feeb2ac976a10016f2f Mon Sep 17 00:00:00 2001
+    From: Oleg Nesterov <oleg at redhat.com>
+    Date: Tue, 30 Nov 2010 20:56:02 +0100
+    Subject: exec: copy-and-paste the fixes into compat_do_execve() paths
+    
+    From: Oleg Nesterov <oleg at redhat.com>
+    
+    commit 114279be2120a916e8a04feeb2ac976a10016f2f upstream.
+    
+    Note: this patch targets 2.6.37 and tries to be as simple as possible.
+    That is why it adds more copy-and-paste horror into fs/compat.c and
+    uglifies fs/exec.c, this will be cleanuped later.
+    
+    compat_copy_strings() plays with bprm->vma/mm directly and thus has
+    two problems: it lacks the RLIMIT_STACK check and argv/envp memory
+    is not visible to oom killer.
+    
+    Export acct_arg_size() and get_arg_page(), change compat_copy_strings()
+    to use get_arg_page(), change compat_do_execve() to do acct_arg_size(0)
+    as do_execve() does.
+    
+    Add the fatal_signal_pending/cond_resched checks into compat_count() and
+    compat_copy_strings(), this matches the code in fs/exec.c and certainly
+    makes sense.
+    
+    Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+    Cc: KOSAKI Motohiro <kosaki.motohiro at jp.fujitsu.com>
+    Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+    Signed-off-by: Andi Kleen <ak at linux.intel.com>
+    [dannf: Backported to Debian's 2.6.26]
+
+diff --git a/fs/compat.c b/fs/compat.c
+index b9efeb1..ed8008c 100644
+--- a/fs/compat.c
++++ b/fs/compat.c
+@@ -1237,6 +1237,10 @@ static int compat_count(compat_uptr_t __user *argv, int max)
+ 			argv++;
+ 			if(++i > max)
+ 				return -E2BIG;
++
++			if (fatal_signal_pending(current))
++				return -ERESTARTNOHAND;
++			cond_resched();
+ 		}
+ 	}
+ 	return i;
+@@ -1278,6 +1282,12 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
+ 		while (len > 0) {
+ 			int offset, bytes_to_copy;
+ 
++			if (fatal_signal_pending(current)) {
++				ret = -ERESTARTNOHAND;
++				goto out;
++			}
++			cond_resched();
++
+ 			offset = pos % PAGE_SIZE;
+ 			if (offset == 0)
+ 				offset = PAGE_SIZE;
+@@ -1294,18 +1304,8 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
+ 			if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+ 				struct page *page;
+ 
+-#ifdef CONFIG_STACK_GROWSUP
+-				ret = expand_stack_downwards(bprm->vma, pos);
+-				if (ret < 0) {
+-					/* We've exceed the stack rlimit. */
+-					ret = -E2BIG;
+-					goto out;
+-				}
+-#endif
+-				ret = get_user_pages(current, bprm->mm, pos,
+-						     1, 1, 1, &page, NULL);
+-				if (ret <= 0) {
+-					/* We've exceed the stack rlimit. */
++				page = get_arg_page(bprm, pos, 1);
++				if (!page) {
+ 					ret = -E2BIG;
+ 					goto out;
+ 				}
+@@ -1414,8 +1414,10 @@ out:
+ 		security_bprm_free(bprm);
+ 
+ out_mm:
+-	if (bprm->mm)
++	if (bprm->mm) {
++		acct_arg_size(bprm, 0);
+ 		mmput(bprm->mm);
++	}
+ 
+ out_file:
+ 	if (bprm->file) {
+diff --git a/fs/exec.c b/fs/exec.c
+index 6ff42ad..ab1bada 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -159,7 +159,7 @@ exit:
+ 
+ #ifdef CONFIG_MMU
+ 
+-static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+ {
+ 	struct mm_struct *mm = current->mm;
+ 	long diff = (long)(pages - bprm->vma_pages);
+@@ -174,7 +174,7 @@ static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+ 	up_write(&mm->mmap_sem);
+ }
+ 
+-static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
++struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		int write)
+ {
+ 	struct page *page;
+@@ -294,11 +294,11 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len)
+ 
+ #else
+ 
+-static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+ {
+ }
+ 
+-static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
++struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		int write)
+ {
+ 	struct page *page;
+diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
+index e700d00..b7b836e 100644
+--- a/include/linux/binfmts.h
++++ b/include/linux/binfmts.h
+@@ -52,6 +52,10 @@ struct linux_binprm{
+ 	unsigned long loader, exec;
+ };
+ 
++extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages);
++extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
++					int write);
++
+ #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
+ #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
+ 

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch	Mon Jan 17 07:12:59 2011	(r16823)
@@ -0,0 +1,121 @@
+commit 91a54ac90fc513b39118a67b0114f83e878a5ca2
+Author: dann frazier <dann.frazier at canonical.com>
+Date:   Wed Jan 12 22:23:19 2011 -0700
+
+    From Oleg Nesterov <oleg at redhat.com>
+    Subject: [PATCH 2.6.35] exec: make argv/envp memory visible to oom-killer
+    
+    From: Oleg Nesterov <oleg at redhat.com>
+    
+    commit 3c77f845722158206a7209c45ccddc264d19319c upstream.
+    
+    Brad Spengler published a local memory-allocation DoS that
+    evades the OOM-killer (though not the virtual memory RLIMIT):
+    http://www.grsecurity.net/~spender/64bit_dos.c
+    
+    execve()->copy_strings() can allocate a lot of memory, but
+    this is not visible to oom-killer, nobody can see the nascent
+    bprm->mm and take it into account.
+    
+    With this patch get_arg_page() increments current's MM_ANONPAGES
+    counter every time we allocate the new page for argv/envp. When
+    do_execve() succeds or fails, we change this counter back.
+    
+    Technically this is not 100% correct, we can't know if the new
+    page is swapped out and turn MM_ANONPAGES into MM_SWAPENTS, but
+    I don't think this really matters and everything becomes correct
+    once exec changes ->mm or fails.
+    
+    Compared to upstream:
+    
+    	before 2.6.36 kernel, oom-killer's badness() takes
+    	mm->total_vm into account and nothing else. So
+    	acct_arg_size() has to play with this counter too.
+    
+    Reported-by: Brad Spengler <spender at grsecurity.net>
+    Signed-off-by: Andi Kleen <ak at linux.intel.com>
+    Reviewed-and-discussed-by: KOSAKI Motohiro <kosaki.motohiro at jp.fujitsu.com>
+    Signed-off-by: Oleg Nesterov <oleg at redhat.com>
+    Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+    [dannf: Backported to Debian's 2.6.26]
+
+diff --git a/fs/exec.c b/fs/exec.c
+index d490980..6ff42ad 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -159,6 +159,21 @@ exit:
+ 
+ #ifdef CONFIG_MMU
+ 
++static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++{
++	struct mm_struct *mm = current->mm;
++	long diff = (long)(pages - bprm->vma_pages);
++
++	if (!mm || !diff)
++		return;
++
++	bprm->vma_pages = pages;
++
++	down_write(&mm->mmap_sem);
++	mm->total_vm += diff;
++	up_write(&mm->mmap_sem);
++}
++
+ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		int write)
+ {
+@@ -181,6 +196,8 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+ 		struct rlimit *rlim;
+ 
++		acct_arg_size(bprm, size / PAGE_SIZE);
++
+ 		/*
+ 		 * We've historically supported up to 32 pages (ARG_MAX)
+ 		 * of argument strings even with small stacks
+@@ -277,6 +294,10 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len)
+ 
+ #else
+ 
++static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++{
++}
++
+ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		int write)
+ {
+@@ -967,6 +988,7 @@ int flush_old_exec(struct linux_binprm * bprm)
+ 	/*
+ 	 * Release all of the old mmap stuff
+ 	 */
++	acct_arg_size(bprm, 0);
+ 	retval = exec_mmap(bprm->mm);
+ 	if (retval)
+ 		goto out;
+@@ -1356,8 +1378,10 @@ out:
+ 		security_bprm_free(bprm);
+ 
+ out_mm:
+-	if (bprm->mm)
+-		mmput (bprm->mm);
++	if (bprm->mm) {
++		acct_arg_size(bprm, 0);
++		mmput(bprm->mm);
++	}
+ 
+ out_file:
+ 	if (bprm->file) {
+diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
+index 6076864..e700d00 100644
+--- a/include/linux/binfmts.h
++++ b/include/linux/binfmts.h
+@@ -28,6 +28,7 @@ struct linux_binprm{
+ 	char buf[BINPRM_BUF_SIZE];
+ #ifdef CONFIG_MMU
+ 	struct vm_area_struct *vma;
++	unsigned long vma_pages;
+ #else
+ # define MAX_ARG_PAGES	32
+ 	struct page *page[MAX_ARG_PAGES];

Added: dists/lenny-security/linux-2.6/debian/patches/debian/exec-Get-rid-of-linux_binprm-vma_pages.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/debian/exec-Get-rid-of-linux_binprm-vma_pages.patch	Mon Jan 17 07:12:59 2011	(r16823)
@@ -0,0 +1,120 @@
+commit 4e23932a029c81d85addac636acce96e9e1f3eab
+Author: dann frazier <dann.frazier at canonical.com>
+Date:   Wed Jan 12 22:30:18 2011 -0700
+
+    From 5e91f59665165f91f97746439e53cc520bb42b97 Mon Sep 17 00:00:00 2001
+    From: Ben Hutchings <ben at decadent.org.uk>
+    Date: Mon, 3 Jan 2011 03:31:58 +0000
+    Subject: [PATCH] exec: Get rid of linux_binprm::vma_pages
+    
+    Adding linux_binprm::vma_pages is an ABI-breaker and we can't hide it
+    because the structure is allocated directly by modules.  However it's
+    just a cache of vma_pages(bprm->vma), so:
+    
+    - We can work out and pass in the old value from get_arg_page()
+    - The calls to acct_arg_size(bprm, 0) are redundant, since
+      neither the cache nor the dead mm need to be updated
+    
+    Signed-off-by: Ben Hutchings <ben at decadent.org.uk>
+    [dannf: Backported to Debian's 2.6.26]
+
+diff --git a/fs/compat.c b/fs/compat.c
+index ed8008c..df5361f 100644
+--- a/fs/compat.c
++++ b/fs/compat.c
+@@ -1415,7 +1415,6 @@ out:
+ 
+ out_mm:
+ 	if (bprm->mm) {
+-		acct_arg_size(bprm, 0);
+ 		mmput(bprm->mm);
+ 	}
+ 
+diff --git a/fs/exec.c b/fs/exec.c
+index ab1bada..6b7c7dd 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -159,16 +159,15 @@ exit:
+ 
+ #ifdef CONFIG_MMU
+ 
+-void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages,
++			  unsigned long old_pages)
+ {
+ 	struct mm_struct *mm = current->mm;
+-	long diff = (long)(pages - bprm->vma_pages);
++	long diff = (long)(pages - old_pages);
+ 
+ 	if (!mm || !diff)
+ 		return;
+ 
+-	bprm->vma_pages = pages;
+-
+ 	down_write(&mm->mmap_sem);
+ 	mm->total_vm += diff;
+ 	up_write(&mm->mmap_sem);
+@@ -177,6 +176,8 @@ void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
+ struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		int write)
+ {
++	unsigned long old_vma_pages =
++		(bprm->vma->vm_end - bprm->vma->vm_start) / PAGE_SIZE;
+ 	struct page *page;
+ 	int ret;
+ 
+@@ -196,7 +197,7 @@ struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+ 		struct rlimit *rlim;
+ 
+-		acct_arg_size(bprm, size / PAGE_SIZE);
++		acct_arg_size(bprm, size / PAGE_SIZE, old_vma_pages);
+ 
+ 		/*
+ 		 * We've historically supported up to 32 pages (ARG_MAX)
+@@ -294,7 +295,8 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len)
+ 
+ #else
+ 
+-void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
++static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages,
++			  unsigned long old_pages)
+ {
+ }
+ 
+@@ -988,7 +990,6 @@ int flush_old_exec(struct linux_binprm * bprm)
+ 	/*
+ 	 * Release all of the old mmap stuff
+ 	 */
+-	acct_arg_size(bprm, 0);
+ 	retval = exec_mmap(bprm->mm);
+ 	if (retval)
+ 		goto out;
+@@ -1379,7 +1380,6 @@ out:
+ 
+ out_mm:
+ 	if (bprm->mm) {
+-		acct_arg_size(bprm, 0);
+ 		mmput(bprm->mm);
+ 	}
+ 
+diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
+index b7b836e..ffb7f1a 100644
+--- a/include/linux/binfmts.h
++++ b/include/linux/binfmts.h
+@@ -28,7 +28,6 @@ struct linux_binprm{
+ 	char buf[BINPRM_BUF_SIZE];
+ #ifdef CONFIG_MMU
+ 	struct vm_area_struct *vma;
+-	unsigned long vma_pages;
+ #else
+ # define MAX_ARG_PAGES	32
+ 	struct page *page[MAX_ARG_PAGES];
+@@ -52,7 +51,6 @@ struct linux_binprm{
+ 	unsigned long loader, exec;
+ };
+ 
+-extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages);
+ extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ 					int write);
+ 

Modified: dists/lenny-security/linux-2.6/debian/patches/series/26lenny2
==============================================================================
--- dists/lenny-security/linux-2.6/debian/patches/series/26lenny2	Sun Jan 16 22:35:15 2011	(r16822)
+++ dists/lenny-security/linux-2.6/debian/patches/series/26lenny2	Mon Jan 17 07:12:59 2011	(r16823)
@@ -7,3 +7,6 @@
 + bugfix/all/CVE-2010-4526.patch
 + bugfix/all/CVE-2010-4527.patch
 + bugfix/all/CVE-2010-4258.patch
++ bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch
++ bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch
++ debian/exec-Get-rid-of-linux_binprm-vma_pages.patch



More information about the Kernel-svn-changes mailing list