[kernel] r16746 - in dists/sid/linux-2.6/debian: . patches/bugfix/all patches/features/all/openvz patches/series
Dann Frazier
dannf at alioth.debian.org
Wed Dec 29 20:52:03 UTC 2010
Author: dannf
Date: Wed Dec 29 20:51:54 2010
New Revision: 16746
Log:
exec: make argv/envp memory visible to oom-killer (CVE-2010-4243)
Added:
dists/sid/linux-2.6/debian/patches/bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer-abi-change.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch
Modified:
dists/sid/linux-2.6/debian/changelog
dists/sid/linux-2.6/debian/patches/features/all/openvz/openvz.patch
dists/sid/linux-2.6/debian/patches/series/30
Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog Wed Dec 29 18:31:18 2010 (r16745)
+++ dists/sid/linux-2.6/debian/changelog Wed Dec 29 20:51:54 2010 (r16746)
@@ -38,6 +38,9 @@
* xen: backport TTM patches to use PCI API. Fixes PCIe GPU (specifically
Radeon and Nouveau) on Xen (Closes: #601341).
+ [ dann frazier ]
+ * exec: make argv/envp memory visible to oom-killer (CVE-2010-4243)
+
-- Ben Hutchings <ben at decadent.org.uk> Sun, 12 Dec 2010 03:23:48 +0000
linux-2.6 (2.6.32-29) unstable; urgency=high
Added: dists/sid/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/sid/linux-2.6/debian/patches/bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch Wed Dec 29 20:51:54 2010 (r16746)
@@ -0,0 +1,149 @@
+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>
+
+---
+ fs/compat.c | 28 +++++++++++++++-------------
+ fs/exec.c | 8 ++++----
+ include/linux/binfmts.h | 4 ++++
+ 3 files changed, 23 insertions(+), 17 deletions(-)
+
+Index: linux/fs/compat.c
+===================================================================
+--- linux.orig/fs/compat.c
++++ linux/fs/compat.c
+@@ -1376,6 +1376,10 @@ static int compat_count(compat_uptr_t __
+ argv++;
+ if (i++ >= max)
+ return -E2BIG;
++
++ if (fatal_signal_pending(current))
++ return -ERESTARTNOHAND;
++ cond_resched();
+ }
+ }
+ return i;
+@@ -1417,6 +1421,12 @@ static int compat_copy_strings(int argc,
+ 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;
+@@ -1433,18 +1443,8 @@ static int compat_copy_strings(int argc,
+ 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;
+ }
+@@ -1565,8 +1565,10 @@ int compat_do_execve(char * filename,
+ return retval;
+
+ out:
+- if (bprm->mm)
++ if (bprm->mm) {
++ acct_arg_size(bprm, 0);
+ mmput(bprm->mm);
++ }
+
+ out_file:
+ if (bprm->file) {
+Index: linux/fs/exec.c
+===================================================================
+--- linux.orig/fs/exec.c
++++ linux/fs/exec.c
+@@ -158,7 +158,7 @@ out:
+
+ #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);
+@@ -173,7 +173,7 @@ static void acct_arg_size(struct linux_b
+ 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;
+@@ -287,11 +287,11 @@ static bool valid_arg_len(struct linux_b
+
+ #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;
+Index: linux/include/linux/binfmts.h
+===================================================================
+--- linux.orig/include/linux/binfmts.h
++++ linux/include/linux/binfmts.h
+@@ -60,6 +60,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/sid/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer-abi-change.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer-abi-change.patch Wed Dec 29 20:51:54 2010 (r16746)
@@ -0,0 +1,23 @@
+diff -urpN oom/include/linux/binfmts.h oom-noabi/include/linux/binfmts.h
+--- oom/include/linux/binfmts.h 2010-12-28 19:07:39.746308959 -0700
++++ oom-noabi/include/linux/binfmts.h 2010-12-28 19:09:49.374136795 -0700
+@@ -29,7 +29,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];
+@@ -58,6 +57,11 @@ struct linux_binprm{
+ unsigned interp_flags;
+ unsigned interp_data;
+ unsigned long loader, exec;
++#ifndef __GENKSYMS__
++#ifdef CONFIG_MMU
++ unsigned long vma_pages;
++#endif
++#endif
+ };
+
+ #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
Added: dists/sid/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/sid/linux-2.6/debian/patches/bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch Wed Dec 29 20:51:54 2010 (r16746)
@@ -0,0 +1,122 @@
+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>
+
+---
+
+ fs/exec.c | 28 ++++++++++++++++++++++++++--
+ include/linux/binfmts.h | 1 +
+ 2 files changed, 27 insertions(+), 2 deletions(-)
+
+Index: linux/include/linux/binfmts.h
+===================================================================
+--- linux.orig/include/linux/binfmts.h
++++ linux/include/linux/binfmts.h
+@@ -29,6 +29,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];
+Index: linux/fs/exec.c
+===================================================================
+--- linux.orig/fs/exec.c
++++ linux/fs/exec.c
+@@ -158,6 +158,21 @@ out:
+
+ #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)
+ {
+@@ -180,6 +195,8 @@ static struct page *get_arg_page(struct
+ 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
+@@ -270,6 +287,10 @@ static bool valid_arg_len(struct linux_b
+
+ #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)
+ {
+@@ -991,6 +1012,7 @@ int flush_old_exec(struct linux_binprm *
+ /*
+ * Release all of the old mmap stuff
+ */
++ acct_arg_size(bprm, 0);
+ retval = exec_mmap(bprm->mm);
+ if (retval)
+ goto out;
+@@ -1415,8 +1437,10 @@ int do_execve(char * filename,
+ return retval;
+
+ out:
+- if (bprm->mm)
+- mmput (bprm->mm);
++ if (bprm->mm) {
++ acct_arg_size(bprm, 0);
++ mmput(bprm->mm);
++ }
+
+ out_file:
+ if (bprm->file) {
Modified: dists/sid/linux-2.6/debian/patches/features/all/openvz/openvz.patch
==============================================================================
--- dists/sid/linux-2.6/debian/patches/features/all/openvz/openvz.patch Wed Dec 29 18:31:18 2010 (r16745)
+++ dists/sid/linux-2.6/debian/patches/features/all/openvz/openvz.patch Wed Dec 29 20:51:54 2010 (r16746)
@@ -16473,10 +16473,10 @@
tsk->group_leader = tsk;
leader->group_leader = tsk;
-@@ -976,12 +1008,10 @@ int flush_old_exec(struct linux_binprm * bprm)
- /*
+@@ -998,12 +1030,10 @@ int flush_old_exec(struct linux_binprm *
* Release all of the old mmap stuff
*/
+ acct_arg_size(bprm, 0);
- retval = exec_mmap(bprm->mm);
+ retval = exec_mmap(bprm);
if (retval)
Modified: dists/sid/linux-2.6/debian/patches/series/30
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/30 Wed Dec 29 18:31:18 2010 (r16745)
+++ dists/sid/linux-2.6/debian/patches/series/30 Wed Dec 29 20:51:54 2010 (r16746)
@@ -19,3 +19,6 @@
+ bugfix/all/iwlwifi-reduce-memory-allocation.patch
+ bugfix/all/drm-radeon-kms-don-t-apply-7xx-hdp-flush-workaround-on-agp.patch
+ bugfix/all/irda-prevent-integer-underflow-in-IRLMP_ENUMDEVICES.patch
++ bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer.patch
++ bugfix/all/exec-make-argv-envp-memory-visible-to-oom-killer-abi-change.patch
++ bugfix/all/exec-copy-and-paste-the-fixes-into-compat_do_execve-paths.patch
More information about the Kernel-svn-changes
mailing list