]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.suse/silent-stack-overflow
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.suse / silent-stack-overflow
CommitLineData
2cb7cef9
BS
1From: Andrea Arcangeli <andrea@suse.de>
2Subject: avoid silent stack overflow over the heap
3Patch-mainline: no
4References: bnc#44807 bnc#211997
5
6x
7
8Signed-off-by: Andrea Arcangeli <andrea@suse.de>
9Updated-by: Jeff Mahoney <jeffm@suse.com>
10---
11
12 arch/alpha/mm/fault.c | 2 -
13 arch/arm/mm/fault.c | 2 -
14 arch/cris/mm/fault.c | 2 -
15 arch/frv/mm/fault.c | 2 -
16 arch/ia64/mm/fault.c | 2 -
17 arch/m32r/mm/fault.c | 2 -
18 arch/m68k/mm/fault.c | 2 -
19 arch/mips/mm/fault.c | 2 -
20 arch/parisc/mm/fault.c | 2 -
21 arch/powerpc/mm/fault.c | 5 ++-
22 arch/powerpc/platforms/cell/spu_fault.c | 2 -
23 arch/s390/mm/fault.c | 2 -
24 arch/sh/mm/fault_32.c | 2 -
25 arch/sh/mm/tlbflush_64.c | 2 -
26 arch/sparc/mm/fault.c | 4 +--
27 arch/sparc64/mm/fault.c | 2 -
28 arch/um/kernel/trap.c | 9 ++++--
29 arch/x86/kernel/sys_x86_64.c | 10 ++++++-
30 arch/x86/mm/fault.c | 10 ++++++-
31 arch/xtensa/mm/fault.c | 2 -
32 include/linux/mm.h | 5 +++
33 kernel/sysctl.c | 8 ++++++
34 mm/mmap.c | 42 +++++++++++++++++++++++++-------
35 23 files changed, 88 insertions(+), 35 deletions(-)
36
37--- a/arch/alpha/mm/fault.c
38+++ b/arch/alpha/mm/fault.c
39@@ -123,7 +123,7 @@ do_page_fault(unsigned long address, uns
40 goto good_area;
41 if (!(vma->vm_flags & VM_GROWSDOWN))
42 goto bad_area;
43- if (expand_stack(vma, address))
44+ if (expand_stack(vma, address, NULL))
45 goto bad_area;
46
47 /* Ok, we have a good vm_area for this memory access, so
48--- a/arch/arm/mm/fault.c
49+++ b/arch/arm/mm/fault.c
50@@ -233,7 +233,7 @@ out_of_memory:
51 goto survive;
52
53 check_stack:
54- if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
55+ if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr, NULL))
56 goto good_area;
57 out:
58 return fault;
59--- a/arch/cris/mm/fault.c
60+++ b/arch/cris/mm/fault.c
61@@ -133,7 +133,7 @@ do_page_fault(unsigned long address, str
62 if (address + PAGE_SIZE < rdusp())
63 goto bad_area;
64 }
65- if (expand_stack(vma, address))
66+ if (expand_stack(vma, address, NULL))
67 goto bad_area;
68
69 /*
70--- a/arch/frv/mm/fault.c
71+++ b/arch/frv/mm/fault.c
72@@ -121,7 +121,7 @@ asmlinkage void do_page_fault(int datamm
73 }
74 }
75
76- if (expand_stack(vma, ear0))
77+ if (expand_stack(vma, ear0, NULL))
78 goto bad_area;
79
80 /*
81--- a/arch/ia64/mm/fault.c
82+++ b/arch/ia64/mm/fault.c
83@@ -185,7 +185,7 @@ ia64_do_page_fault (unsigned long addres
84 if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)
85 || REGION_OFFSET(address) >= RGN_MAP_LIMIT)
86 goto bad_area;
87- if (expand_stack(vma, address))
88+ if (expand_stack(vma, address, NULL /* FIXME? */))
89 goto bad_area;
90 } else {
91 vma = prev_vma;
92--- a/arch/m32r/mm/fault.c
93+++ b/arch/m32r/mm/fault.c
94@@ -159,7 +159,7 @@ asmlinkage void do_page_fault(struct pt_
95 goto bad_area;
96 }
97
98- if (expand_stack(vma, address))
99+ if (expand_stack(vma, address, NULL))
100 goto bad_area;
101 /*
102 * Ok, we have a good vm_area for this memory access, so
103--- a/arch/m68k/mm/fault.c
104+++ b/arch/m68k/mm/fault.c
105@@ -121,7 +121,7 @@ int do_page_fault(struct pt_regs *regs,
106 if (address + 256 < rdusp())
107 goto map_err;
108 }
109- if (expand_stack(vma, address))
110+ if (expand_stack(vma, address, NULL))
111 goto map_err;
112
113 /*
114--- a/arch/mips/mm/fault.c
115+++ b/arch/mips/mm/fault.c
116@@ -80,7 +80,7 @@ asmlinkage void do_page_fault(struct pt_
117 goto good_area;
118 if (!(vma->vm_flags & VM_GROWSDOWN))
119 goto bad_area;
120- if (expand_stack(vma, address))
121+ if (expand_stack(vma, address, NULL))
122 goto bad_area;
123 /*
124 * Ok, we have a good vm_area for this memory access, so
125--- a/arch/parisc/mm/fault.c
126+++ b/arch/parisc/mm/fault.c
127@@ -196,7 +196,7 @@ good_area:
128
129 check_expansion:
130 vma = prev_vma;
131- if (vma && (expand_stack(vma, address) == 0))
132+ if (vma && (expand_stack(vma, address, NULL) == 0))
133 goto good_area;
134
135 /*
136--- a/arch/powerpc/mm/fault.c
137+++ b/arch/powerpc/mm/fault.c
138@@ -116,7 +116,7 @@ static int store_updates_sp(struct pt_re
139 int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
140 unsigned long error_code)
141 {
142- struct vm_area_struct * vma;
143+ struct vm_area_struct * vma, * prev_vma;
144 struct mm_struct *mm = current->mm;
145 siginfo_t info;
146 int code = SEGV_MAPERR;
147@@ -230,7 +230,8 @@ int __kprobes do_page_fault(struct pt_re
148 && (!user_mode(regs) || !store_updates_sp(regs)))
149 goto bad_area;
150 }
151- if (expand_stack(vma, address))
152+ find_vma_prev(mm, address, &prev_vma);
153+ if (expand_stack(vma, address, prev_vma))
154 goto bad_area;
155
156 good_area:
157--- a/arch/powerpc/platforms/cell/spu_fault.c
158+++ b/arch/powerpc/platforms/cell/spu_fault.c
159@@ -59,7 +59,7 @@ int spu_handle_mm_fault(struct mm_struct
160 goto good_area;
161 if (!(vma->vm_flags & VM_GROWSDOWN))
162 goto bad_area;
163- if (expand_stack(vma, ea))
164+ if (expand_stack(vma, ea, NULL))
165 goto bad_area;
166 good_area:
167 is_write = dsisr & MFC_DSISR_ACCESS_PUT;
168--- a/arch/s390/mm/fault.c
169+++ b/arch/s390/mm/fault.c
170@@ -350,7 +350,7 @@ do_exception(struct pt_regs *regs, unsig
171 goto good_area;
172 if (!(vma->vm_flags & VM_GROWSDOWN))
173 goto bad_area;
174- if (expand_stack(vma, address))
175+ if (expand_stack(vma, address, NULL /* FIXME? */))
176 goto bad_area;
177 /*
178 * Ok, we have a good vm_area for this memory access, so
179--- a/arch/sh/mm/fault_32.c
180+++ b/arch/sh/mm/fault_32.c
181@@ -108,7 +108,7 @@ asmlinkage void __kprobes do_page_fault(
182 goto good_area;
183 if (!(vma->vm_flags & VM_GROWSDOWN))
184 goto bad_area;
185- if (expand_stack(vma, address))
186+ if (expand_stack(vma, address, NULL))
187 goto bad_area;
188 /*
189 * Ok, we have a good vm_area for this memory access, so
190--- a/arch/sh/mm/tlbflush_64.c
191+++ b/arch/sh/mm/tlbflush_64.c
192@@ -153,7 +153,7 @@ asmlinkage void do_page_fault(struct pt_
193 #endif
194 goto bad_area;
195 }
196- if (expand_stack(vma, address)) {
197+ if (expand_stack(vma, address, NULL)) {
198 #ifdef DEBUG_FAULT
199 print_task(tsk);
200 printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
201--- a/arch/sparc/mm/fault.c
202+++ b/arch/sparc/mm/fault.c
203@@ -219,7 +219,7 @@ asmlinkage void do_sparc_fault(struct pt
204 goto good_area;
205 if(!(vma->vm_flags & VM_GROWSDOWN))
206 goto bad_area;
207- if(expand_stack(vma, address))
208+ if(expand_stack(vma, address, NULL))
209 goto bad_area;
210 /*
211 * Ok, we have a good vm_area for this memory access, so
212@@ -472,7 +472,7 @@ static void force_user_fault(unsigned lo
213 goto good_area;
214 if(!(vma->vm_flags & VM_GROWSDOWN))
215 goto bad_area;
216- if(expand_stack(vma, address))
217+ if(expand_stack(vma, address, NULL))
218 goto bad_area;
219 good_area:
220 info.si_code = SEGV_ACCERR;
221--- a/arch/sparc64/mm/fault.c
222+++ b/arch/sparc64/mm/fault.c
223@@ -367,7 +367,7 @@ continue_fault:
224 goto bad_area;
225 }
226 }
227- if (expand_stack(vma, address))
228+ if (expand_stack(vma, address, NULL))
229 goto bad_area;
230 /*
231 * Ok, we have a good vm_area for this memory access, so
232--- a/arch/um/kernel/trap.c
233+++ b/arch/um/kernel/trap.c
234@@ -24,7 +24,7 @@ int handle_page_fault(unsigned long addr
235 int is_write, int is_user, int *code_out)
236 {
237 struct mm_struct *mm = current->mm;
238- struct vm_area_struct *vma;
239+ struct vm_area_struct *vma, *prev_vma;
240 pgd_t *pgd;
241 pud_t *pud;
242 pmd_t *pmd;
243@@ -50,8 +50,11 @@ int handle_page_fault(unsigned long addr
244 goto out;
245 else if (is_user && !ARCH_IS_STACKGROW(address))
246 goto out;
247- else if (expand_stack(vma, address))
248- goto out;
249+ else {
250+ find_vma_prev(mm, address, &prev_vma);
251+ if(expand_stack(vma, address, prev_vma))
252+ goto out;
253+ }
254
255 good_area:
256 *code_out = SEGV_ACCERR;
257--- a/arch/x86/kernel/sys_x86_64.c
258+++ b/arch/x86/kernel/sys_x86_64.c
259@@ -106,6 +106,7 @@ arch_get_unmapped_area(struct file *filp
260
261 full_search:
262 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
263+ unsigned long __heap_stack_gap;
264 /* At this point: (!vma || addr < vma->vm_end). */
265 if (end - len < addr) {
266 /*
267@@ -119,7 +120,14 @@ full_search:
268 }
269 return -ENOMEM;
270 }
271- if (!vma || addr + len <= vma->vm_start) {
272+ if (!vma)
273+ goto got_it;
274+ __heap_stack_gap = 0;
275+ if (vma->vm_flags & VM_GROWSDOWN)
276+ __heap_stack_gap = min(end-(addr+len),
277+ (unsigned long) heap_stack_gap << PAGE_SHIFT);
278+ if (addr + len + __heap_stack_gap <= vma->vm_start) {
279+ got_it:
280 /*
281 * Remember the place where we stopped the search:
282 */
283--- a/arch/x86/mm/fault.c
284+++ b/arch/x86/mm/fault.c
285@@ -585,7 +585,7 @@ void __kprobes do_page_fault(struct pt_r
286 {
287 struct task_struct *tsk;
288 struct mm_struct *mm;
289- struct vm_area_struct *vma;
290+ struct vm_area_struct *vma, *prev_vma;
291 unsigned long address;
292 int write, si_code;
293 int fault;
294@@ -719,7 +719,13 @@ again:
295 if (address + 65536 + 32 * sizeof(unsigned long) < regs->sp)
296 goto bad_area;
297 }
298- if (expand_stack(vma, address))
299+ /*
300+ * find_vma_prev is just a bit slower, because it cannot
301+ * use the mmap_cache, so we run it only in the growsdown
302+ * slow path and we leave find_vma in the fast path.
303+ */
304+ find_vma_prev(current->mm, address, &prev_vma);
305+ if (expand_stack(vma, address, prev_vma))
306 goto bad_area;
307 /*
308 * Ok, we have a good vm_area for this memory access, so
309--- a/arch/xtensa/mm/fault.c
310+++ b/arch/xtensa/mm/fault.c
311@@ -80,7 +80,7 @@ void do_page_fault(struct pt_regs *regs)
312 goto good_area;
313 if (!(vma->vm_flags & VM_GROWSDOWN))
314 goto bad_area;
315- if (expand_stack(vma, address))
316+ if (expand_stack(vma, address, NULL))
317 goto bad_area;
318
319 /* Ok, we have a good vm_area for this memory access, so
320--- a/include/linux/mm.h
321+++ b/include/linux/mm.h
322@@ -1208,7 +1208,10 @@ void page_cache_async_readahead(struct a
323 unsigned long max_sane_readahead(unsigned long nr);
324
325 /* Do stack extension */
326-extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
327+#define EXPAND_STACK_HAS_3_ARGS
328+extern int heap_stack_gap;
329+extern int expand_stack(struct vm_area_struct * vma, unsigned long address,
330+ struct vm_area_struct * prev_vma);
331 #ifdef CONFIG_IA64
332 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
333 #endif
334--- a/kernel/sysctl.c
335+++ b/kernel/sysctl.c
336@@ -1208,6 +1208,14 @@ static struct ctl_table vm_table[] = {
337 .extra2 = &one,
338 },
339 #endif
340+ {
341+ .ctl_name = CTL_UNNUMBERED,
342+ .procname = "heap-stack-gap",
343+ .data = &heap_stack_gap,
344+ .maxlen = sizeof(int),
345+ .mode = 0644,
346+ .proc_handler = &proc_dointvec,
347+ },
348 /*
349 * NOTE: do not add new entries to this table unless you have read
350 * Documentation/sysctl/ctl_unnumbered.txt
351--- a/mm/mmap.c
352+++ b/mm/mmap.c
353@@ -85,6 +85,7 @@ int sysctl_overcommit_memory = OVERCOMMI
354 int sysctl_overcommit_ratio = 50; /* default is 50% */
355 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
356 atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0);
357+int heap_stack_gap = 1;
358
359 /*
360 * Check that a process has enough memory to allocate a new virtual
361@@ -1291,6 +1292,7 @@ arch_get_unmapped_area(struct file *filp
362 full_search:
363 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
364 /* At this point: (!vma || addr < vma->vm_end). */
365+ unsigned long __heap_stack_gap;
366 if (TASK_SIZE - len < addr) {
367 /*
368 * Start a new search - just in case we missed
369@@ -1304,7 +1306,14 @@ full_search:
370 }
371 return -ENOMEM;
372 }
373- if (!vma || addr + len <= vma->vm_start) {
374+ if (!vma)
375+ goto got_it;
376+ __heap_stack_gap = 0;
377+ if (vma->vm_flags & VM_GROWSDOWN)
378+ __heap_stack_gap = min(TASK_SIZE-(addr+len),
379+ (unsigned long) heap_stack_gap << PAGE_SHIFT);
380+ if (addr + len + __heap_stack_gap <= vma->vm_start) {
381+ got_it:
382 /*
383 * Remember the place where we stopped the search:
384 */
385@@ -1633,11 +1642,9 @@ int expand_upwards(struct vm_area_struct
386 }
387 #endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */
388
389-/*
390- * vma is the first one with address < vma->vm_start. Have to extend vma.
391- */
392 static inline int expand_downwards(struct vm_area_struct *vma,
393- unsigned long address)
394+ unsigned long address,
395+ struct vm_area_struct *prev_vma)
396 {
397 int error;
398
399@@ -1665,6 +1672,13 @@ static inline int expand_downwards(struc
400 if (address < vma->vm_start) {
401 unsigned long size, grow;
402
403+ error = -ENOMEM;
404+ if (prev_vma) {
405+ unsigned long __heap_stack_gap = min(TASK_SIZE-prev_vma->vm_end,
406+ (unsigned long) heap_stack_gap << PAGE_SHIFT);
407+ if (unlikely(prev_vma->vm_end + __heap_stack_gap > address))
408+ goto out_unlock;
409+ }
410 size = vma->vm_end - address;
411 grow = (vma->vm_start - address) >> PAGE_SHIFT;
412
413@@ -1674,6 +1688,7 @@ static inline int expand_downwards(struc
414 vma->vm_pgoff -= grow;
415 }
416 }
417+ out_unlock:
418 anon_vma_unlock(vma);
419 return error;
420 }
421@@ -1684,8 +1699,16 @@ int expand_stack_downwards(struct vm_are
422 }
423
424 #ifdef CONFIG_STACK_GROWSUP
425-int expand_stack(struct vm_area_struct *vma, unsigned long address)
426+int expand_stack(struct vm_area_struct * vma, unsigned long address,
427+ struct vm_area_struct * prev_vma)
428 {
429+ /*
430+ * If you re-use the heap-stack-gap for a growsup stack you
431+ * should implement the feature for growsup too and remove
432+ * this WARN_ON.
433+ */
434+ WARN_ON(prev_vma);
435+
436 return expand_upwards(vma, address);
437 }
438
439@@ -1698,7 +1721,7 @@ find_extend_vma(struct mm_struct *mm, un
440 vma = find_vma_prev(mm, addr, &prev);
441 if (vma && (vma->vm_start <= addr))
442 return vma;
443- if (!prev || expand_stack(prev, addr))
444+ if (!prev || expand_stack(prev, addr, NULL))
445 return NULL;
446 if (prev->vm_flags & VM_LOCKED)
447 make_pages_present(addr, prev->vm_end);
448@@ -1713,7 +1736,7 @@ int expand_stack(struct vm_area_struct *
449 struct vm_area_struct *
450 find_extend_vma(struct mm_struct * mm, unsigned long addr)
451 {
452- struct vm_area_struct * vma;
453+ struct vm_area_struct * vma, * prev_vma;
454 unsigned long start;
455
456 addr &= PAGE_MASK;
457@@ -1725,7 +1748,8 @@ find_extend_vma(struct mm_struct * mm, u
458 if (!(vma->vm_flags & VM_GROWSDOWN))
459 return NULL;
460 start = vma->vm_start;
461- if (expand_stack(vma, addr))
462+ find_vma_prev(mm, addr, &prev_vma);
463+ if (expand_stack(vma, addr, prev_vma))
464 return NULL;
465 if (vma->vm_flags & VM_LOCKED)
466 make_pages_present(addr, start);