]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.36.2/exec-make-argv-envp-memory-visible-to-oom-killer.patch
Remove duplicated commits
[thirdparty/kernel/stable-queue.git] / releases / 2.6.36.2 / exec-make-argv-envp-memory-visible-to-oom-killer.patch
1 From 3c77f845722158206a7209c45ccddc264d19319c Mon Sep 17 00:00:00 2001
2 From: Oleg Nesterov <oleg@redhat.com>
3 Date: Tue, 30 Nov 2010 20:55:34 +0100
4 Subject: exec: make argv/envp memory visible to oom-killer
5
6 From: Oleg Nesterov <oleg@redhat.com>
7
8 commit 3c77f845722158206a7209c45ccddc264d19319c upstream.
9
10 Brad Spengler published a local memory-allocation DoS that
11 evades the OOM-killer (though not the virtual memory RLIMIT):
12 http://www.grsecurity.net/~spender/64bit_dos.c
13
14 execve()->copy_strings() can allocate a lot of memory, but
15 this is not visible to oom-killer, nobody can see the nascent
16 bprm->mm and take it into account.
17
18 With this patch get_arg_page() increments current's MM_ANONPAGES
19 counter every time we allocate the new page for argv/envp. When
20 do_execve() succeds or fails, we change this counter back.
21
22 Technically this is not 100% correct, we can't know if the new
23 page is swapped out and turn MM_ANONPAGES into MM_SWAPENTS, but
24 I don't think this really matters and everything becomes correct
25 once exec changes ->mm or fails.
26
27 Reported-by: Brad Spengler <spender@grsecurity.net>
28 Reviewed-and-discussed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
29 Signed-off-by: Oleg Nesterov <oleg@redhat.com>
30 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
31 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
32
33 ---
34 fs/exec.c | 32 ++++++++++++++++++++++++++++++--
35 include/linux/binfmts.h | 1 +
36 2 files changed, 31 insertions(+), 2 deletions(-)
37
38 --- a/fs/exec.c
39 +++ b/fs/exec.c
40 @@ -157,6 +157,25 @@ out:
41
42 #ifdef CONFIG_MMU
43
44 +static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
45 +{
46 + struct mm_struct *mm = current->mm;
47 + long diff = (long)(pages - bprm->vma_pages);
48 +
49 + if (!mm || !diff)
50 + return;
51 +
52 + bprm->vma_pages = pages;
53 +
54 +#ifdef SPLIT_RSS_COUNTING
55 + add_mm_counter(mm, MM_ANONPAGES, diff);
56 +#else
57 + spin_lock(&mm->page_table_lock);
58 + add_mm_counter(mm, MM_ANONPAGES, diff);
59 + spin_unlock(&mm->page_table_lock);
60 +#endif
61 +}
62 +
63 static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
64 int write)
65 {
66 @@ -179,6 +198,8 @@ static struct page *get_arg_page(struct
67 unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
68 struct rlimit *rlim;
69
70 + acct_arg_size(bprm, size / PAGE_SIZE);
71 +
72 /*
73 * We've historically supported up to 32 pages (ARG_MAX)
74 * of argument strings even with small stacks
75 @@ -269,6 +290,10 @@ static bool valid_arg_len(struct linux_b
76
77 #else
78
79 +static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
80 +{
81 +}
82 +
83 static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
84 int write)
85 {
86 @@ -992,6 +1017,7 @@ int flush_old_exec(struct linux_binprm *
87 /*
88 * Release all of the old mmap stuff
89 */
90 + acct_arg_size(bprm, 0);
91 retval = exec_mmap(bprm->mm);
92 if (retval)
93 goto out;
94 @@ -1416,8 +1442,10 @@ int do_execve(const char * filename,
95 return retval;
96
97 out:
98 - if (bprm->mm)
99 - mmput (bprm->mm);
100 + if (bprm->mm) {
101 + acct_arg_size(bprm, 0);
102 + mmput(bprm->mm);
103 + }
104
105 out_file:
106 if (bprm->file) {
107 --- a/include/linux/binfmts.h
108 +++ b/include/linux/binfmts.h
109 @@ -29,6 +29,7 @@ struct linux_binprm{
110 char buf[BINPRM_BUF_SIZE];
111 #ifdef CONFIG_MMU
112 struct vm_area_struct *vma;
113 + unsigned long vma_pages;
114 #else
115 # define MAX_ARG_PAGES 32
116 struct page *page[MAX_ARG_PAGES];