[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