summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2017-11-16 09:38:47 +0100
committerAdrian Dudau <adrian.dudau@enea.com>2017-11-16 12:00:54 +0100
commit63e1243bb63d15cbf58cafa7caab00599ed8f46c (patch)
tree6ce141ad9d3ba5712fac9b6de3f9b5fdc885a261
parentcf3664b57f0dc010c27bce1103c89c22dc359641 (diff)
downloadmeta-enea-bsp-x86-pyro.tar.gz
linu-intel: CVE-2017-1000364pyro
Fixes an issue in the size of the stack guard page on Linux, specifically a 4k stack guard page is not sufficiently large and can be "jumped" over (the stack guard page is bypassed), this affects Linux Kernel versions 4.11.5 and earlier. References: https://nvd.nist.gov/vuln/detail/CVE-2017-1000364 https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2017-1000364 https://blogs.oracle.com/wim/cve-2017-1000364 Upstream patch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?h=v4.9.50&id=cfc0eb403816c5c4f9667d959de5e22789b5421e Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
-rw-r--r--recipes-kernel/linux/linux-intel.inc1
-rw-r--r--recipes-kernel/linux/linux-intel/CVE-2017-1000364.patch939
2 files changed, 940 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-intel.inc b/recipes-kernel/linux/linux-intel.inc
index 84fbf77..c335a57 100644
--- a/recipes-kernel/linux/linux-intel.inc
+++ b/recipes-kernel/linux/linux-intel.inc
@@ -6,6 +6,7 @@ SRCREV_metaenea = "7579efbdb49529f36652b69d4630c6c43907f77b"
6KENEABRANCH = "intel-4.9" 6KENEABRANCH = "intel-4.9"
7SRC_URI_append = " git://git@git.enea.com/linux/enea-kernel-cache.git;protocol=ssh;type=kmeta;name=metaenea;branch=${KENEABRANCH};destsuffix=enea-kernel-meta \ 7SRC_URI_append = " git://git@git.enea.com/linux/enea-kernel-cache.git;protocol=ssh;type=kmeta;name=metaenea;branch=${KENEABRANCH};destsuffix=enea-kernel-meta \
8 file://CVE-2017-11176.patch \ 8 file://CVE-2017-11176.patch \
9 file://CVE-2017-1000364.patch \
9 " 10 "
10 11
11KERNEL_FEATURES_append = " features/udev/udev.scc" 12KERNEL_FEATURES_append = " features/udev/udev.scc"
diff --git a/recipes-kernel/linux/linux-intel/CVE-2017-1000364.patch b/recipes-kernel/linux/linux-intel/CVE-2017-1000364.patch
new file mode 100644
index 0000000..a25dd45
--- /dev/null
+++ b/recipes-kernel/linux/linux-intel/CVE-2017-1000364.patch
@@ -0,0 +1,939 @@
1From cfc0eb403816c5c4f9667d959de5e22789b5421e Mon Sep 17 00:00:00 2001
2From: Hugh Dickins <hughd@google.com>
3Date: Mon, 19 Jun 2017 04:03:24 -0700
4Subject: [PATCH] mm: larger stack guard gap, between vmas
5
6commit 1be7107fbe18eed3e319a6c3e83c78254b693acb upstream.
7
8Stack guard page is a useful feature to reduce a risk of stack smashing
9into a different mapping. We have been using a single page gap which
10is sufficient to prevent having stack adjacent to a different mapping.
11But this seems to be insufficient in the light of the stack usage in
12userspace. E.g. glibc uses as large as 64kB alloca() in many commonly
13used functions. Others use constructs liks gid_t buffer[NGROUPS_MAX]
14which is 256kB or stack strings with MAX_ARG_STRLEN.
15
16This will become especially dangerous for suid binaries and the default
17no limit for the stack size limit because those applications can be
18tricked to consume a large portion of the stack and a single glibc call
19could jump over the guard page. These attacks are not theoretical,
20unfortunatelly.
21
22Make those attacks less probable by increasing the stack guard gap
23to 1MB (on systems with 4k pages; but make it depend on the page size
24because systems with larger base pages might cap stack allocations in
25the PAGE_SIZE units) which should cover larger alloca() and VLA stack
26allocations. It is obviously not a full fix because the problem is
27somehow inherent, but it should reduce attack space a lot.
28
29One could argue that the gap size should be configurable from userspace,
30but that can be done later when somebody finds that the new 1MB is wrong
31for some special case applications. For now, add a kernel command line
32option (stack_guard_gap) to specify the stack gap size (in page units).
33
34Implementation wise, first delete all the old code for stack guard page:
35because although we could get away with accounting one extra page in a
36stack vma, accounting a larger gap can break userspace - case in point,
37a program run with "ulimit -S -v 20000" failed when the 1MB gap was
38counted for RLIMIT_AS; similar problems could come with RLIMIT_MLOCK
39and strict non-overcommit mode.
40
41Instead of keeping gap inside the stack vma, maintain the stack guard
42gap as a gap between vmas: using vm_start_gap() in place of vm_start
43(or vm_end_gap() in place of vm_end if VM_GROWSUP) in just those few
44places which need to respect the gap - mainly arch_get_unmapped_area(),
45and and the vma tree's subtree_gap support for that.
46
47CVE: CVE-2017-1000364
48Upstream-Status: Backport [backport from https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?h=v4.9.50&id=cfc0eb403816c5c4f9667d959de5e22789b5421e]
49
50Original-patch-by: Oleg Nesterov <oleg@redhat.com>
51Original-patch-by: Michal Hocko <mhocko@suse.com>
52Signed-off-by: Hugh Dickins <hughd@google.com>
53Acked-by: Michal Hocko <mhocko@suse.com>
54Tested-by: Helge Deller <deller@gmx.de> # parisc
55Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
56[wt: backport to 4.11: adjust context]
57[wt: backport to 4.9: adjust context ; kernel doc was not in admin-guide]
58Signed-off-by: Willy Tarreau <w@1wt.eu>
59Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
60Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
61---
62 Documentation/kernel-parameters.txt | 7 ++
63 arch/arc/mm/mmap.c | 2 +-
64 arch/arm/mm/mmap.c | 4 +-
65 arch/frv/mm/elf-fdpic.c | 2 +-
66 arch/mips/mm/mmap.c | 2 +-
67 arch/parisc/kernel/sys_parisc.c | 15 ++--
68 arch/powerpc/mm/hugetlbpage-radix.c | 2 +-
69 arch/powerpc/mm/mmap.c | 4 +-
70 arch/powerpc/mm/slice.c | 2 +-
71 arch/s390/mm/mmap.c | 4 +-
72 arch/sh/mm/mmap.c | 4 +-
73 arch/sparc/kernel/sys_sparc_64.c | 4 +-
74 arch/sparc/mm/hugetlbpage.c | 2 +-
75 arch/tile/mm/hugetlbpage.c | 2 +-
76 arch/x86/kernel/sys_x86_64.c | 4 +-
77 arch/x86/mm/hugetlbpage.c | 2 +-
78 arch/xtensa/kernel/syscall.c | 2 +-
79 fs/hugetlbfs/inode.c | 2 +-
80 fs/proc/task_mmu.c | 4 -
81 include/linux/mm.h | 53 ++++++-------
82 mm/gup.c | 5 --
83 mm/memory.c | 38 ---------
84 mm/mmap.c | 149 +++++++++++++++++++++---------------
85 23 files changed, 152 insertions(+), 163 deletions(-)
86
87diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
88index a6fadef..86a6746 100644
89--- a/Documentation/kernel-parameters.txt
90+++ b/Documentation/kernel-parameters.txt
91@@ -3932,6 +3932,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
92 spia_pedr=
93 spia_peddr=
94
95+ stack_guard_gap= [MM]
96+ override the default stack gap protection. The value
97+ is in page units and it defines how many pages prior
98+ to (for stacks growing down) resp. after (for stacks
99+ growing up) the main stack are reserved for no other
100+ mapping. Default value is 256 pages.
101+
102 stacktrace [FTRACE]
103 Enabled the stack tracer on boot up.
104
105diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c
106index 2e06d56..cf4ae69 100644
107--- a/arch/arc/mm/mmap.c
108+++ b/arch/arc/mm/mmap.c
109@@ -64,7 +64,7 @@
110
111 vma = find_vma(mm, addr);
112 if (TASK_SIZE - len >= addr &&
113- (!vma || addr + len <= vma->vm_start))
114+ (!vma || addr + len <= vm_start_gap(vma)))
115 return addr;
116 }
117
118diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
119index 66353ca..641334e 100644
120--- a/arch/arm/mm/mmap.c
121+++ b/arch/arm/mm/mmap.c
122@@ -89,7 +89,7 @@ static unsigned long mmap_base(unsigned long rnd)
123
124 vma = find_vma(mm, addr);
125 if (TASK_SIZE - len >= addr &&
126- (!vma || addr + len <= vma->vm_start))
127+ (!vma || addr + len <= vm_start_gap(vma)))
128 return addr;
129 }
130
131@@ -140,7 +140,7 @@ static unsigned long mmap_base(unsigned long rnd)
132 addr = PAGE_ALIGN(addr);
133 vma = find_vma(mm, addr);
134 if (TASK_SIZE - len >= addr &&
135- (!vma || addr + len <= vma->vm_start))
136+ (!vma || addr + len <= vm_start_gap(vma)))
137 return addr;
138 }
139
140diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c
141index 836f1470..efa59f1 100644
142--- a/arch/frv/mm/elf-fdpic.c
143+++ b/arch/frv/mm/elf-fdpic.c
144@@ -74,7 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
145 addr = PAGE_ALIGN(addr);
146 vma = find_vma(current->mm, addr);
147 if (TASK_SIZE - len >= addr &&
148- (!vma || addr + len <= vma->vm_start))
149+ (!vma || addr + len <= vm_start_gap(vma)))
150 goto success;
151 }
152
153diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
154index d08ea3f..a44052c 100644
155--- a/arch/mips/mm/mmap.c
156+++ b/arch/mips/mm/mmap.c
157@@ -92,7 +92,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp,
158
159 vma = find_vma(mm, addr);
160 if (TASK_SIZE - len >= addr &&
161- (!vma || addr + len <= vma->vm_start))
162+ (!vma || addr + len <= vm_start_gap(vma)))
163 return addr;
164 }
165
166diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
167index 0a393a0..1d7691f 100644
168--- a/arch/parisc/kernel/sys_parisc.c
169+++ b/arch/parisc/kernel/sys_parisc.c
170@@ -88,7 +88,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
171 unsigned long len, unsigned long pgoff, unsigned long flags)
172 {
173 struct mm_struct *mm = current->mm;
174- struct vm_area_struct *vma;
175+ struct vm_area_struct *vma, *prev;
176 unsigned long task_size = TASK_SIZE;
177 int do_color_align, last_mmap;
178 struct vm_unmapped_area_info info;
179@@ -115,9 +115,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
180 else
181 addr = PAGE_ALIGN(addr);
182
183- vma = find_vma(mm, addr);
184+ vma = find_vma_prev(mm, addr, &prev);
185 if (task_size - len >= addr &&
186- (!vma || addr + len <= vma->vm_start))
187+ (!vma || addr + len <= vm_start_gap(vma)) &&
188+ (!prev || addr >= vm_end_gap(prev)))
189 goto found_addr;
190 }
191
192@@ -141,7 +142,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
193 const unsigned long len, const unsigned long pgoff,
194 const unsigned long flags)
195 {
196- struct vm_area_struct *vma;
197+ struct vm_area_struct *vma, *prev;
198 struct mm_struct *mm = current->mm;
199 unsigned long addr = addr0;
200 int do_color_align, last_mmap;
201@@ -175,9 +176,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
202 addr = COLOR_ALIGN(addr, last_mmap, pgoff);
203 else
204 addr = PAGE_ALIGN(addr);
205- vma = find_vma(mm, addr);
206+
207+ vma = find_vma_prev(mm, addr, &prev);
208 if (TASK_SIZE - len >= addr &&
209- (!vma || addr + len <= vma->vm_start))
210+ (!vma || addr + len <= vm_start_gap(vma)) &&
211+ (!prev || addr >= vm_end_gap(prev)))
212 goto found_addr;
213 }
214
215diff --git a/arch/powerpc/mm/hugetlbpage-radix.c b/arch/powerpc/mm/hugetlbpage-radix.c
216index 35254a6..a2b2d97 100644
217--- a/arch/powerpc/mm/hugetlbpage-radix.c
218+++ b/arch/powerpc/mm/hugetlbpage-radix.c
219@@ -65,7 +65,7 @@ void radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long st
220 addr = ALIGN(addr, huge_page_size(h));
221 vma = find_vma(mm, addr);
222 if (TASK_SIZE - len >= addr &&
223- (!vma || addr + len <= vma->vm_start))
224+ (!vma || addr + len <= vm_start_gap(vma)))
225 return addr;
226 }
227 /*
228diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c
229index 2f1e443..5bc2845 100644
230--- a/arch/powerpc/mm/mmap.c
231+++ b/arch/powerpc/mm/mmap.c
232@@ -106,7 +106,7 @@ static inline unsigned long mmap_base(unsigned long rnd)
233 addr = PAGE_ALIGN(addr);
234 vma = find_vma(mm, addr);
235 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
236- (!vma || addr + len <= vma->vm_start))
237+ (!vma || addr + len <= vm_start_gap(vma)))
238 return addr;
239 }
240
241@@ -142,7 +142,7 @@ static inline unsigned long mmap_base(unsigned long rnd)
242 addr = PAGE_ALIGN(addr);
243 vma = find_vma(mm, addr);
244 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
245- (!vma || addr + len <= vma->vm_start))
246+ (!vma || addr + len <= vm_start_gap(vma)))
247 return addr;
248 }
249
250diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
251index 2b27458..c4d5c9c 100644
252--- a/arch/powerpc/mm/slice.c
253+++ b/arch/powerpc/mm/slice.c
254@@ -105,7 +105,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
255 if ((mm->task_size - len) < addr)
256 return 0;
257 vma = find_vma(mm, addr);
258- return (!vma || (addr + len) <= vma->vm_start);
259+ return (!vma || (addr + len) <= vm_start_gap(vma));
260 }
261
262 static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
263diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
264index eb9df28..812368f 100644
265--- a/arch/s390/mm/mmap.c
266+++ b/arch/s390/mm/mmap.c
267@@ -98,7 +98,7 @@ static inline unsigned long mmap_base(unsigned long rnd)
268 addr = PAGE_ALIGN(addr);
269 vma = find_vma(mm, addr);
270 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
271- (!vma || addr + len <= vma->vm_start))
272+ (!vma || addr + len <= vm_start_gap(vma)))
273 return addr;
274 }
275
276@@ -136,7 +136,7 @@ static inline unsigned long mmap_base(unsigned long rnd)
277 addr = PAGE_ALIGN(addr);
278 vma = find_vma(mm, addr);
279 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
280- (!vma || addr + len <= vma->vm_start))
281+ (!vma || addr + len <= vm_start_gap(vma)))
282 return addr;
283 }
284
285diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c
286index 6777177..7df7d59 100644
287--- a/arch/sh/mm/mmap.c
288+++ b/arch/sh/mm/mmap.c
289@@ -63,7 +63,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
290
291 vma = find_vma(mm, addr);
292 if (TASK_SIZE - len >= addr &&
293- (!vma || addr + len <= vma->vm_start))
294+ (!vma || addr + len <= vm_start_gap(vma)))
295 return addr;
296 }
297
298@@ -113,7 +113,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
299
300 vma = find_vma(mm, addr);
301 if (TASK_SIZE - len >= addr &&
302- (!vma || addr + len <= vma->vm_start))
303+ (!vma || addr + len <= vm_start_gap(vma)))
304 return addr;
305 }
306
307diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
308index fe8b8ee..02e05e2 100644
309--- a/arch/sparc/kernel/sys_sparc_64.c
310+++ b/arch/sparc/kernel/sys_sparc_64.c
311@@ -118,7 +118,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
312
313 vma = find_vma(mm, addr);
314 if (task_size - len >= addr &&
315- (!vma || addr + len <= vma->vm_start))
316+ (!vma || addr + len <= vm_start_gap(vma)))
317 return addr;
318 }
319
320@@ -181,7 +181,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
321
322 vma = find_vma(mm, addr);
323 if (task_size - len >= addr &&
324- (!vma || addr + len <= vma->vm_start))
325+ (!vma || addr + len <= vm_start_gap(vma)))
326 return addr;
327 }
328
329diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c
330index 988acc8b..58cde8d 100644
331--- a/arch/sparc/mm/hugetlbpage.c
332+++ b/arch/sparc/mm/hugetlbpage.c
333@@ -116,7 +116,7 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp,
334 addr = ALIGN(addr, HPAGE_SIZE);
335 vma = find_vma(mm, addr);
336 if (task_size - len >= addr &&
337- (!vma || addr + len <= vma->vm_start))
338+ (!vma || addr + len <= vm_start_gap(vma)))
339 return addr;
340 }
341 if (mm->get_unmapped_area == arch_get_unmapped_area)
342diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c
343index 77ceaa3..67508b2 100644
344--- a/arch/tile/mm/hugetlbpage.c
345+++ b/arch/tile/mm/hugetlbpage.c
346@@ -232,7 +232,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
347 addr = ALIGN(addr, huge_page_size(h));
348 vma = find_vma(mm, addr);
349 if (TASK_SIZE - len >= addr &&
350- (!vma || addr + len <= vma->vm_start))
351+ (!vma || addr + len <= vm_start_gap(vma)))
352 return addr;
353 }
354 if (current->mm->get_unmapped_area == arch_get_unmapped_area)
355diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
356index a55ed63..1119414 100644
357--- a/arch/x86/kernel/sys_x86_64.c
358+++ b/arch/x86/kernel/sys_x86_64.c
359@@ -140,7 +140,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
360 addr = PAGE_ALIGN(addr);
361 vma = find_vma(mm, addr);
362 if (end - len >= addr &&
363- (!vma || addr + len <= vma->vm_start))
364+ (!vma || addr + len <= vm_start_gap(vma)))
365 return addr;
366 }
367
368@@ -183,7 +183,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
369 addr = PAGE_ALIGN(addr);
370 vma = find_vma(mm, addr);
371 if (TASK_SIZE - len >= addr &&
372- (!vma || addr + len <= vma->vm_start))
373+ (!vma || addr + len <= vm_start_gap(vma)))
374 return addr;
375 }
376
377diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
378index 2ae8584..fe342e8 100644
379--- a/arch/x86/mm/hugetlbpage.c
380+++ b/arch/x86/mm/hugetlbpage.c
381@@ -144,7 +144,7 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
382 addr = ALIGN(addr, huge_page_size(h));
383 vma = find_vma(mm, addr);
384 if (TASK_SIZE - len >= addr &&
385- (!vma || addr + len <= vma->vm_start))
386+ (!vma || addr + len <= vm_start_gap(vma)))
387 return addr;
388 }
389 if (mm->get_unmapped_area == arch_get_unmapped_area)
390diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
391index 83cf496..3aaaae1 100644
392--- a/arch/xtensa/kernel/syscall.c
393+++ b/arch/xtensa/kernel/syscall.c
394@@ -87,7 +87,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
395 /* At this point: (!vmm || addr < vmm->vm_end). */
396 if (TASK_SIZE - len < addr)
397 return -ENOMEM;
398- if (!vmm || addr + len <= vmm->vm_start)
399+ if (!vmm || addr + len <= vm_start_gap(vmm))
400 return addr;
401 addr = vmm->vm_end;
402 if (flags & MAP_SHARED)
403diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
404index 4fb7b10..704fa0b 100644
405--- a/fs/hugetlbfs/inode.c
406+++ b/fs/hugetlbfs/inode.c
407@@ -191,7 +191,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
408 addr = ALIGN(addr, huge_page_size(h));
409 vma = find_vma(mm, addr);
410 if (TASK_SIZE - len >= addr &&
411- (!vma || addr + len <= vma->vm_start))
412+ (!vma || addr + len <= vm_start_gap(vma)))
413 return addr;
414 }
415
416diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
417index b1517b6..5138e78 100644
418--- a/fs/proc/task_mmu.c
419+++ b/fs/proc/task_mmu.c
420@@ -299,11 +299,7 @@ static int is_stack(struct proc_maps_private *priv,
421
422 /* We don't show the stack guard page in /proc/maps */
423 start = vma->vm_start;
424- if (stack_guard_page_start(vma, start))
425- start += PAGE_SIZE;
426 end = vma->vm_end;
427- if (stack_guard_page_end(vma, end))
428- end -= PAGE_SIZE;
429
430 seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
431 seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
432diff --git a/include/linux/mm.h b/include/linux/mm.h
433index 0b5b2e4..6c9e1ad 100644
434--- a/include/linux/mm.h
435+++ b/include/linux/mm.h
436@@ -1356,39 +1356,11 @@ void account_page_cleaned(struct page *page, struct address_space *mapping,
437
438 int get_cmdline(struct task_struct *task, char *buffer, int buflen);
439
440-/* Is the vma a continuation of the stack vma above it? */
441-static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
442-{
443- return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN);
444-}
445-
446 static inline bool vma_is_anonymous(struct vm_area_struct *vma)
447 {
448 return !vma->vm_ops;
449 }
450
451-static inline int stack_guard_page_start(struct vm_area_struct *vma,
452- unsigned long addr)
453-{
454- return (vma->vm_flags & VM_GROWSDOWN) &&
455- (vma->vm_start == addr) &&
456- !vma_growsdown(vma->vm_prev, addr);
457-}
458-
459-/* Is the vma a continuation of the stack vma below it? */
460-static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr)
461-{
462- return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP);
463-}
464-
465-static inline int stack_guard_page_end(struct vm_area_struct *vma,
466- unsigned long addr)
467-{
468- return (vma->vm_flags & VM_GROWSUP) &&
469- (vma->vm_end == addr) &&
470- !vma_growsup(vma->vm_next, addr);
471-}
472-
473 int vma_is_stack_for_current(struct vm_area_struct *vma);
474
475 extern unsigned long move_page_tables(struct vm_area_struct *vma,
476@@ -2127,6 +2099,7 @@ void page_cache_async_readahead(struct address_space *mapping,
477 pgoff_t offset,
478 unsigned long size);
479
480+extern unsigned long stack_guard_gap;
481 /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
482 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
483
484@@ -2155,6 +2128,30 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m
485 return vma;
486 }
487
488+static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
489+{
490+ unsigned long vm_start = vma->vm_start;
491+
492+ if (vma->vm_flags & VM_GROWSDOWN) {
493+ vm_start -= stack_guard_gap;
494+ if (vm_start > vma->vm_start)
495+ vm_start = 0;
496+ }
497+ return vm_start;
498+}
499+
500+static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
501+{
502+ unsigned long vm_end = vma->vm_end;
503+
504+ if (vma->vm_flags & VM_GROWSUP) {
505+ vm_end += stack_guard_gap;
506+ if (vm_end < vma->vm_end)
507+ vm_end = -PAGE_SIZE;
508+ }
509+ return vm_end;
510+}
511+
512 static inline unsigned long vma_pages(struct vm_area_struct *vma)
513 {
514 return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
515diff --git a/mm/gup.c b/mm/gup.c
516index ec4f827..c63a034 100644
517--- a/mm/gup.c
518+++ b/mm/gup.c
519@@ -370,11 +370,6 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
520 /* mlock all present pages, but do not fault in new pages */
521 if ((*flags & (FOLL_POPULATE | FOLL_MLOCK)) == FOLL_MLOCK)
522 return -ENOENT;
523- /* For mm_populate(), just skip the stack guard page. */
524- if ((*flags & FOLL_POPULATE) &&
525- (stack_guard_page_start(vma, address) ||
526- stack_guard_page_end(vma, address + PAGE_SIZE)))
527- return -ENOENT;
528 if (*flags & FOLL_WRITE)
529 fault_flags |= FAULT_FLAG_WRITE;
530 if (*flags & FOLL_REMOTE)
531diff --git a/mm/memory.c b/mm/memory.c
532index cbb1e5e..e6a5a1f 100644
533--- a/mm/memory.c
534+++ b/mm/memory.c
535@@ -2699,40 +2699,6 @@ int do_swap_page(struct fault_env *fe, pte_t orig_pte)
536 }
537
538 /*
539- * This is like a special single-page "expand_{down|up}wards()",
540- * except we must first make sure that 'address{-|+}PAGE_SIZE'
541- * doesn't hit another vma.
542- */
543-static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address)
544-{
545- address &= PAGE_MASK;
546- if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) {
547- struct vm_area_struct *prev = vma->vm_prev;
548-
549- /*
550- * Is there a mapping abutting this one below?
551- *
552- * That's only ok if it's the same stack mapping
553- * that has gotten split..
554- */
555- if (prev && prev->vm_end == address)
556- return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
557-
558- return expand_downwards(vma, address - PAGE_SIZE);
559- }
560- if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
561- struct vm_area_struct *next = vma->vm_next;
562-
563- /* As VM_GROWSDOWN but s/below/above/ */
564- if (next && next->vm_start == address + PAGE_SIZE)
565- return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
566-
567- return expand_upwards(vma, address + PAGE_SIZE);
568- }
569- return 0;
570-}
571-
572-/*
573 * We enter with non-exclusive mmap_sem (to exclude vma changes,
574 * but allow concurrent faults), and pte mapped but not yet locked.
575 * We return with mmap_sem still held, but pte unmapped and unlocked.
576@@ -2748,10 +2714,6 @@ static int do_anonymous_page(struct fault_env *fe)
577 if (vma->vm_flags & VM_SHARED)
578 return VM_FAULT_SIGBUS;
579
580- /* Check if we need to add a guard page to the stack */
581- if (check_stack_guard_page(vma, fe->address) < 0)
582- return VM_FAULT_SIGSEGV;
583-
584 /*
585 * Use pte_alloc() instead of pte_alloc_map(). We can't run
586 * pte_offset_map() on pmds where a huge pmd might be created
587diff --git a/mm/mmap.c b/mm/mmap.c
588index 1af87c1..26542b3 100644
589--- a/mm/mmap.c
590+++ b/mm/mmap.c
591@@ -183,6 +183,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
592 unsigned long retval;
593 unsigned long newbrk, oldbrk;
594 struct mm_struct *mm = current->mm;
595+ struct vm_area_struct *next;
596 unsigned long min_brk;
597 bool populate;
598
599@@ -228,7 +229,8 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
600 }
601
602 /* Check against existing mmap mappings. */
603- if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
604+ next = find_vma(mm, oldbrk);
605+ if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
606 goto out;
607
608 /* Ok, looks good - let it rip. */
609@@ -251,10 +253,22 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
610
611 static long vma_compute_subtree_gap(struct vm_area_struct *vma)
612 {
613- unsigned long max, subtree_gap;
614- max = vma->vm_start;
615- if (vma->vm_prev)
616- max -= vma->vm_prev->vm_end;
617+ unsigned long max, prev_end, subtree_gap;
618+
619+ /*
620+ * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we
621+ * allow two stack_guard_gaps between them here, and when choosing
622+ * an unmapped area; whereas when expanding we only require one.
623+ * That's a little inconsistent, but keeps the code here simpler.
624+ */
625+ max = vm_start_gap(vma);
626+ if (vma->vm_prev) {
627+ prev_end = vm_end_gap(vma->vm_prev);
628+ if (max > prev_end)
629+ max -= prev_end;
630+ else
631+ max = 0;
632+ }
633 if (vma->vm_rb.rb_left) {
634 subtree_gap = rb_entry(vma->vm_rb.rb_left,
635 struct vm_area_struct, vm_rb)->rb_subtree_gap;
636@@ -350,7 +364,7 @@ static void validate_mm(struct mm_struct *mm)
637 anon_vma_unlock_read(anon_vma);
638 }
639
640- highest_address = vma->vm_end;
641+ highest_address = vm_end_gap(vma);
642 vma = vma->vm_next;
643 i++;
644 }
645@@ -539,7 +553,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
646 if (vma->vm_next)
647 vma_gap_update(vma->vm_next);
648 else
649- mm->highest_vm_end = vma->vm_end;
650+ mm->highest_vm_end = vm_end_gap(vma);
651
652 /*
653 * vma->vm_prev wasn't known when we followed the rbtree to find the
654@@ -854,7 +868,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
655 vma_gap_update(vma);
656 if (end_changed) {
657 if (!next)
658- mm->highest_vm_end = end;
659+ mm->highest_vm_end = vm_end_gap(vma);
660 else if (!adjust_next)
661 vma_gap_update(next);
662 }
663@@ -939,7 +953,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
664 * mm->highest_vm_end doesn't need any update
665 * in remove_next == 1 case.
666 */
667- VM_WARN_ON(mm->highest_vm_end != end);
668+ VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma));
669 }
670 }
671 if (insert && file)
672@@ -1783,7 +1797,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info)
673
674 while (true) {
675 /* Visit left subtree if it looks promising */
676- gap_end = vma->vm_start;
677+ gap_end = vm_start_gap(vma);
678 if (gap_end >= low_limit && vma->vm_rb.rb_left) {
679 struct vm_area_struct *left =
680 rb_entry(vma->vm_rb.rb_left,
681@@ -1794,7 +1808,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info)
682 }
683 }
684
685- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
686+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
687 check_current:
688 /* Check if current node has a suitable gap */
689 if (gap_start > high_limit)
690@@ -1821,8 +1835,8 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info)
691 vma = rb_entry(rb_parent(prev),
692 struct vm_area_struct, vm_rb);
693 if (prev == vma->vm_rb.rb_left) {
694- gap_start = vma->vm_prev->vm_end;
695- gap_end = vma->vm_start;
696+ gap_start = vm_end_gap(vma->vm_prev);
697+ gap_end = vm_start_gap(vma);
698 goto check_current;
699 }
700 }
701@@ -1886,7 +1900,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
702
703 while (true) {
704 /* Visit right subtree if it looks promising */
705- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0;
706+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
707 if (gap_start <= high_limit && vma->vm_rb.rb_right) {
708 struct vm_area_struct *right =
709 rb_entry(vma->vm_rb.rb_right,
710@@ -1899,7 +1913,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
711
712 check_current:
713 /* Check if current node has a suitable gap */
714- gap_end = vma->vm_start;
715+ gap_end = vm_start_gap(vma);
716 if (gap_end < low_limit)
717 return -ENOMEM;
718 if (gap_start <= high_limit && gap_end - gap_start >= length)
719@@ -1925,7 +1939,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
720 struct vm_area_struct, vm_rb);
721 if (prev == vma->vm_rb.rb_right) {
722 gap_start = vma->vm_prev ?
723- vma->vm_prev->vm_end : 0;
724+ vm_end_gap(vma->vm_prev) : 0;
725 goto check_current;
726 }
727 }
728@@ -1963,7 +1977,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
729 unsigned long len, unsigned long pgoff, unsigned long flags)
730 {
731 struct mm_struct *mm = current->mm;
732- struct vm_area_struct *vma;
733+ struct vm_area_struct *vma, *prev;
734 struct vm_unmapped_area_info info;
735
736 if (len > TASK_SIZE - mmap_min_addr)
737@@ -1974,9 +1988,10 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
738
739 if (addr) {
740 addr = PAGE_ALIGN(addr);
741- vma = find_vma(mm, addr);
742+ vma = find_vma_prev(mm, addr, &prev);
743 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
744- (!vma || addr + len <= vma->vm_start))
745+ (!vma || addr + len <= vm_start_gap(vma)) &&
746+ (!prev || addr >= vm_end_gap(prev)))
747 return addr;
748 }
749
750@@ -1999,7 +2014,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
751 const unsigned long len, const unsigned long pgoff,
752 const unsigned long flags)
753 {
754- struct vm_area_struct *vma;
755+ struct vm_area_struct *vma, *prev;
756 struct mm_struct *mm = current->mm;
757 unsigned long addr = addr0;
758 struct vm_unmapped_area_info info;
759@@ -2014,9 +2029,10 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
760 /* requesting a specific address */
761 if (addr) {
762 addr = PAGE_ALIGN(addr);
763- vma = find_vma(mm, addr);
764+ vma = find_vma_prev(mm, addr, &prev);
765 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
766- (!vma || addr + len <= vma->vm_start))
767+ (!vma || addr + len <= vm_start_gap(vma)) &&
768+ (!prev || addr >= vm_end_gap(prev)))
769 return addr;
770 }
771
772@@ -2151,21 +2167,19 @@ struct vm_area_struct *
773 * update accounting. This is shared with both the
774 * grow-up and grow-down cases.
775 */
776-static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow)
777+static int acct_stack_growth(struct vm_area_struct *vma,
778+ unsigned long size, unsigned long grow)
779 {
780 struct mm_struct *mm = vma->vm_mm;
781 struct rlimit *rlim = current->signal->rlim;
782- unsigned long new_start, actual_size;
783+ unsigned long new_start;
784
785 /* address space limit tests */
786 if (!may_expand_vm(mm, vma->vm_flags, grow))
787 return -ENOMEM;
788
789 /* Stack limit test */
790- actual_size = size;
791- if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN)))
792- actual_size -= PAGE_SIZE;
793- if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
794+ if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
795 return -ENOMEM;
796
797 /* mlock limit tests */
798@@ -2203,17 +2217,30 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
799 int expand_upwards(struct vm_area_struct *vma, unsigned long address)
800 {
801 struct mm_struct *mm = vma->vm_mm;
802+ struct vm_area_struct *next;
803+ unsigned long gap_addr;
804 int error = 0;
805
806 if (!(vma->vm_flags & VM_GROWSUP))
807 return -EFAULT;
808
809 /* Guard against wrapping around to address 0. */
810- if (address < PAGE_ALIGN(address+4))
811- address = PAGE_ALIGN(address+4);
812- else
813+ address &= PAGE_MASK;
814+ address += PAGE_SIZE;
815+ if (!address)
816 return -ENOMEM;
817
818+ /* Enforce stack_guard_gap */
819+ gap_addr = address + stack_guard_gap;
820+ if (gap_addr < address)
821+ return -ENOMEM;
822+ next = vma->vm_next;
823+ if (next && next->vm_start < gap_addr) {
824+ if (!(next->vm_flags & VM_GROWSUP))
825+ return -ENOMEM;
826+ /* Check that both stack segments have the same anon_vma? */
827+ }
828+
829 /* We must make sure the anon_vma is allocated. */
830 if (unlikely(anon_vma_prepare(vma)))
831 return -ENOMEM;
832@@ -2257,7 +2284,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
833 if (vma->vm_next)
834 vma_gap_update(vma->vm_next);
835 else
836- mm->highest_vm_end = address;
837+ mm->highest_vm_end = vm_end_gap(vma);
838 spin_unlock(&mm->page_table_lock);
839
840 perf_event_mmap(vma);
841@@ -2278,6 +2305,8 @@ int expand_downwards(struct vm_area_struct *vma,
842 unsigned long address)
843 {
844 struct mm_struct *mm = vma->vm_mm;
845+ struct vm_area_struct *prev;
846+ unsigned long gap_addr;
847 int error;
848
849 address &= PAGE_MASK;
850@@ -2285,6 +2314,17 @@ int expand_downwards(struct vm_area_struct *vma,
851 if (error)
852 return error;
853
854+ /* Enforce stack_guard_gap */
855+ gap_addr = address - stack_guard_gap;
856+ if (gap_addr > address)
857+ return -ENOMEM;
858+ prev = vma->vm_prev;
859+ if (prev && prev->vm_end > gap_addr) {
860+ if (!(prev->vm_flags & VM_GROWSDOWN))
861+ return -ENOMEM;
862+ /* Check that both stack segments have the same anon_vma? */
863+ }
864+
865 /* We must make sure the anon_vma is allocated. */
866 if (unlikely(anon_vma_prepare(vma)))
867 return -ENOMEM;
868@@ -2339,28 +2379,25 @@ int expand_downwards(struct vm_area_struct *vma,
869 return error;
870 }
871
872-/*
873- * Note how expand_stack() refuses to expand the stack all the way to
874- * abut the next virtual mapping, *unless* that mapping itself is also
875- * a stack mapping. We want to leave room for a guard page, after all
876- * (the guard page itself is not added here, that is done by the
877- * actual page faulting logic)
878- *
879- * This matches the behavior of the guard page logic (see mm/memory.c:
880- * check_stack_guard_page()), which only allows the guard page to be
881- * removed under these circumstances.
882- */
883+/* enforced gap between the expanding stack and other mappings. */
884+unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
885+
886+static int __init cmdline_parse_stack_guard_gap(char *p)
887+{
888+ unsigned long val;
889+ char *endptr;
890+
891+ val = simple_strtoul(p, &endptr, 10);
892+ if (!*endptr)
893+ stack_guard_gap = val << PAGE_SHIFT;
894+
895+ return 0;
896+}
897+__setup("stack_guard_gap=", cmdline_parse_stack_guard_gap);
898+
899 #ifdef CONFIG_STACK_GROWSUP
900 int expand_stack(struct vm_area_struct *vma, unsigned long address)
901 {
902- struct vm_area_struct *next;
903-
904- address &= PAGE_MASK;
905- next = vma->vm_next;
906- if (next && next->vm_start == address + PAGE_SIZE) {
907- if (!(next->vm_flags & VM_GROWSUP))
908- return -ENOMEM;
909- }
910 return expand_upwards(vma, address);
911 }
912
913@@ -2382,14 +2419,6 @@ struct vm_area_struct *
914 #else
915 int expand_stack(struct vm_area_struct *vma, unsigned long address)
916 {
917- struct vm_area_struct *prev;
918-
919- address &= PAGE_MASK;
920- prev = vma->vm_prev;
921- if (prev && prev->vm_end == address) {
922- if (!(prev->vm_flags & VM_GROWSDOWN))
923- return -ENOMEM;
924- }
925 return expand_downwards(vma, address);
926 }
927
928@@ -2487,7 +2516,7 @@ static void unmap_region(struct mm_struct *mm,
929 vma->vm_prev = prev;
930 vma_gap_update(vma);
931 } else
932- mm->highest_vm_end = prev ? prev->vm_end : 0;
933+ mm->highest_vm_end = prev ? vm_end_gap(prev) : 0;
934 tail_vma->vm_next = NULL;
935
936 /* Kill the cache */
937--
9381.9.1
939