From a6e570898bf252dab4e1a2b3f8403e05096f06e6 Mon Sep 17 00:00:00 2001 From: Zhang Xiao Date: Fri, 23 Jun 2017 12:45:42 +0800 Subject: [PATCH] WR5 linux-windriver: preliminary fix to CVE-2017-100364 CVE-2017-100365 CVE: CVE-2017-100364 CVE-2017-100365 See included patch for more details on the changes. Signed-off-by: Zhang Xiao --- .../0001-mm-enlarge-stack-guard-gap.patch | 503 +++++++++++++++++++++ ...-the-stack-gap-for-unpopulated-growing-vm.patch | 54 +++ ...0003-mm-allow-to-configure-stack-gap-size.patch | 143 ++++++ ...004-mm-do-not-collapse-stack-gap-into-THP.patch | 67 +++ recipes-kernel/linux/linux-windriver_3.4.bb | 8 +- 5 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 recipes-kernel/linux/linux-windriver/0001-mm-enlarge-stack-guard-gap.patch create mode 100644 recipes-kernel/linux/linux-windriver/0002-mm-proc-cap-the-stack-gap-for-unpopulated-growing-vm.patch create mode 100644 recipes-kernel/linux/linux-windriver/0003-mm-allow-to-configure-stack-gap-size.patch create mode 100644 recipes-kernel/linux/linux-windriver/0004-mm-do-not-collapse-stack-gap-into-THP.patch diff --git a/recipes-kernel/linux/linux-windriver/0001-mm-enlarge-stack-guard-gap.patch b/recipes-kernel/linux/linux-windriver/0001-mm-enlarge-stack-guard-gap.patch new file mode 100644 index 0000000..81cbcb6 --- /dev/null +++ b/recipes-kernel/linux/linux-windriver/0001-mm-enlarge-stack-guard-gap.patch @@ -0,0 +1,503 @@ +From 6b00dc0e82f0d500e2a2287d02d6719ed5733d55 Mon Sep 17 00:00:00 2001 +From: Michal Hocko +Date: Wed, 14 Jun 2017 08:16:54 +0200 +Subject: [PATCH 1/4] mm: enlarge stack guard gap + +Stack guard page is a useful feature to reduce a risk of stack smashing +into a different mapping. We have been using a single page gap which is +sufficient to prevent having stack adjacent to a different mapping. But +this seems to be insufficient in the light of the stack usage in the +userspace. E.g. glibc uses as large as 64kB alloca() in many commonly +used functions. Others use constructs liks gid_t buffer[NGROUPS_MAX] +which is 256kB or stack strings with MAX_ARG_STRLEN. + +This will become especially dangerous for suid binaries and the default +no limit for the stack size limit because those applications can be +tricked to consume a large portion of the stack and a single glibc call +could jump over the guard page. These attacks are not theoretical, +unfortunatelly. + +Make those attacks less probable by increasing the stack guard gap to +1MB (on systems with 4k pages but make it depend on the page size +because systems with larger base pages might cap stack allocations in +the PAGE_SIZE units) which should cover larger alloca() and VLA stack +allocations. It is obviously not a full fix because the problem is +somehow inherent but it should reduce attack space a lot. One could +argue that the gap size should be configurable from the userspace but +that can be done later on top when somebody finds that the new 1MB is +not suitable or even wrong for some special case applications. + +Implementation wise, get rid of check_stack_guard_page and move all the +guard page specific code to expandable_stack_area which always tries to +guarantee the gap. do_anonymous_page then just calls expand_stack. +Also get rid of stack_guard_page_{start,end} and replace them with +stack_guard_area to handle stack population and /proc//[s]maps. + +This should clean up the code which is quite scattered currently and +therefore justify the change. + +Signed-off-by: Michal Hocko +Tested-by: Tony Luck # ia64 +Tested-by: Laura Abbott +Tested-by: Helge Deller # parisc +Signed-off-by: Linus Torvalds +Cc: Ben Hutchings +[wt: backport to 4.9 : s/vmf->address/fe->address/] +[wt: backport to 4.4 : + s/fe->address/address/ ; s/FOLL_POPULATE/FOLL_MLOCK ] +[wt: backport to 3.10 : adjust context ; + s/stack_guard_page()/stack_guard_area() ] +Signed-off-by: Willy Tarreau +Signed-off-by: Zhang Xiao +--- + arch/ia64/mm/fault.c | 2 +- + fs/exec.c | 8 ++- + fs/proc/task_mmu.c | 11 ++-- + include/linux/mm.h | 38 ++----------- + mm/memory.c | 48 ++-------------- + mm/mmap.c | 156 +++++++++++++++++++++++++++++++++++++++++++-------- + 6 files changed, 158 insertions(+), 105 deletions(-) + +diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c +index 02d29c2..037cd4f 100644 +--- a/arch/ia64/mm/fault.c ++++ b/arch/ia64/mm/fault.c +@@ -197,7 +197,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re + */ + if (address > vma->vm_end + PAGE_SIZE - sizeof(long)) + goto bad_area; +- if (expand_upwards(vma, address)) ++ if (expand_upwards(vma, address, 0)) + goto bad_area; + } + goto good_area; +diff --git a/fs/exec.c b/fs/exec.c +index 645734f..537f683 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -201,7 +201,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + + #ifdef CONFIG_STACK_GROWSUP + if (write) { +- ret = expand_downwards(bprm->vma, pos); ++ ret = expand_downwards(bprm->vma, pos, 0); + if (ret < 0) + return NULL; + } +@@ -215,6 +215,12 @@ 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; + ++ /* ++ * GROWSUP doesn't really have any gap at this stage because we grow ++ * the stack down now. See the expand_downwards above. ++ */ ++ if (!IS_ENABLED(CONFIG_STACK_GROWSUP)) ++ size -= stack_guard_gap; + acct_arg_size(bprm, size / PAGE_SIZE); + + /* +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 8df7fd2..f2bae95 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -233,11 +233,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + + /* We don't show the stack guard page in /proc/maps */ + start = vma->vm_start; +- if (stack_guard_page_start(vma, start)) +- start += PAGE_SIZE; + end = vma->vm_end; +- if (stack_guard_page_end(vma, end)) +- end -= PAGE_SIZE; ++ if (vma->vm_flags & VM_GROWSDOWN) { ++ if (stack_guard_area(vma, start)) ++ start += stack_guard_gap; ++ } else if (vma->vm_flags & VM_GROWSUP) { ++ if (stack_guard_area(vma, end)) ++ end -= stack_guard_gap; ++ } + + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", + start, +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 9d8e204..0c6cefe 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1014,34 +1014,6 @@ int set_page_dirty(struct page *page); + int set_page_dirty_lock(struct page *page); + int clear_page_dirty_for_io(struct page *page); + +-/* Is the vma a continuation of the stack vma above it? */ +-static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) +-{ +- return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); +-} +- +-static inline int stack_guard_page_start(struct vm_area_struct *vma, +- unsigned long addr) +-{ +- return (vma->vm_flags & VM_GROWSDOWN) && +- (vma->vm_start == addr) && +- !vma_growsdown(vma->vm_prev, addr); +-} +- +-/* Is the vma a continuation of the stack vma below it? */ +-static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) +-{ +- return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); +-} +- +-static inline int stack_guard_page_end(struct vm_area_struct *vma, +- unsigned long addr) +-{ +- return (vma->vm_flags & VM_GROWSUP) && +- (vma->vm_end == addr) && +- !vma_growsup(vma->vm_next, addr); +-} +- + extern pid_t + vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group); + +@@ -1445,17 +1417,19 @@ unsigned long max_sane_readahead(unsigned long nr); + unsigned long ra_submit(struct file_ra_state *ra, + struct address_space *mapping, + struct file *filp); +- ++extern unsigned long stack_guard_gap; + /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ + extern int expand_stack(struct vm_area_struct *vma, unsigned long address); ++extern int stack_guard_area(struct vm_area_struct *vma, unsigned long address); + + /* CONFIG_STACK_GROWSUP still needs to to grow downwards at some places */ + extern int expand_downwards(struct vm_area_struct *vma, +- unsigned long address); ++ unsigned long address, unsigned long gap); + #if VM_GROWSUP +-extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); ++extern int expand_upwards(struct vm_area_struct *vma, ++ unsigned long address, unsigned long gap); + #else +- #define expand_upwards(vma, address) do { } while (0) ++ #define expand_upwards(vma, address, gap) do { } while (0) + #endif + + /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ +diff --git a/mm/memory.c b/mm/memory.c +index 13b2bce..88edeb6 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1624,12 +1624,6 @@ no_page_table: + return page; + } + +-static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) +-{ +- return stack_guard_page_start(vma, addr) || +- stack_guard_page_end(vma, addr+PAGE_SIZE); +-} +- + /** + * __get_user_pages() - pin user pages in memory + * @tsk: task_struct of target task +@@ -1782,7 +1776,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, + + /* For mlock, just skip the stack guard page. */ + if (foll_flags & FOLL_MLOCK) { +- if (stack_guard_page(vma, start)) ++ if (stack_guard_area(vma, start)) + goto next_page; + } + trace_page_fault_get_user_entry(mm, +@@ -3140,40 +3134,6 @@ out_release: + } + + /* +- * This is like a special single-page "expand_{down|up}wards()", +- * except we must first make sure that 'address{-|+}PAGE_SIZE' +- * doesn't hit another vma. +- */ +-static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) +-{ +- address &= PAGE_MASK; +- if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { +- struct vm_area_struct *prev = vma->vm_prev; +- +- /* +- * Is there a mapping abutting this one below? +- * +- * That's only ok if it's the same stack mapping +- * that has gotten split.. +- */ +- if (prev && prev->vm_end == address) +- return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; +- +- expand_downwards(vma, address - PAGE_SIZE); +- } +- if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { +- struct vm_area_struct *next = vma->vm_next; +- +- /* As VM_GROWSDOWN but s/below/above/ */ +- if (next && next->vm_start == address + PAGE_SIZE) +- return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; +- +- expand_upwards(vma, address + PAGE_SIZE); +- } +- return 0; +-} +- +-/* + * We enter with non-exclusive mmap_sem (to exclude vma changes, + * but allow concurrent faults), and pte mapped but not yet locked. + * We return with mmap_sem still held, but pte unmapped and unlocked. +@@ -3193,8 +3153,10 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, + return VM_FAULT_SIGBUS; + + /* Check if we need to add a guard page to the stack */ +- if (check_stack_guard_page(vma, address) < 0) +- return VM_FAULT_SIGBUS; ++ if (stack_guard_area(vma, address)) { ++ if (expand_stack(vma, address) < 0) ++ return VM_FAULT_SIGBUS; ++ } + + /* Use the zero-page for reads */ + if (!(flags & FAULT_FLAG_WRITE)) { +diff --git a/mm/mmap.c b/mm/mmap.c +index 2e6d0ea..56cf13f 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -1745,18 +1745,22 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr, + * update accounting. This is shared with both the + * grow-up and grow-down cases. + */ +-static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) ++static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow, ++ unsigned long gap) + { + struct mm_struct *mm = vma->vm_mm; + struct rlimit *rlim = current->signal->rlim; +- unsigned long new_start; ++ unsigned long new_start, actual_size;; + + /* address space limit tests */ + if (!may_expand_vm(mm, grow)) + return -ENOMEM; + + /* Stack limit test */ +- if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) ++ actual_size = size; ++ if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) ++ actual_size -= gap; ++ if (actual_size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) + return -ENOMEM; + + /* mlock limit tests */ +@@ -1796,7 +1800,7 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns + * PA-RISC uses this for its stack; IA64 for its Register Backing Store. + * vma is the last one with address > vma->vm_end. Have to extend vma. + */ +-int expand_upwards(struct vm_area_struct *vma, unsigned long address) ++int expand_upwards(struct vm_area_struct *vma, unsigned long address, unsigned long gap) + { + int error; + +@@ -1834,7 +1838,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) + + error = -ENOMEM; + if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) { +- error = acct_stack_growth(vma, size, grow); ++ error = acct_stack_growth(vma, size, grow, gap); + if (!error) { + vma->vm_end = address; + perf_event_mmap(vma); +@@ -1851,7 +1855,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) + * vma is the first one with address < vma->vm_start. Have to extend vma. + */ + int expand_downwards(struct vm_area_struct *vma, +- unsigned long address) ++ unsigned long address, unsigned long gap) + { + int error; + +@@ -1884,7 +1888,7 @@ int expand_downwards(struct vm_area_struct *vma, + + error = -ENOMEM; + if (grow <= vma->vm_pgoff) { +- error = acct_stack_growth(vma, size, grow); ++ error = acct_stack_growth(vma, size, grow, gap); + if (!error) { + vma->vm_start = address; + vma->vm_pgoff -= grow; +@@ -1897,29 +1901,77 @@ int expand_downwards(struct vm_area_struct *vma, + return error; + } + ++/* enforced gap between the expanding stack and other mappings. */ ++unsigned long stack_guard_gap = 256UL<vm_next; ++ unsigned long guard_gap = stack_guard_gap; ++ unsigned long guard_addr; ++ ++ /* don't exceed address space */ ++ if (address >= TASK_SIZE) ++ return -ENOMEM; ++ ++ address = PAGE_ALIGN(address); ++ ++ if (!next) ++ goto out; ++ ++ if (next->vm_flags & VM_GROWSUP) { ++ guard_gap = min(guard_gap, next->vm_start - address); ++ goto out; ++ } ++ ++ if (next->vm_start - address < guard_gap) ++ return -ENOMEM; ++out: ++ if (TASK_SIZE - address < guard_gap) ++ guard_gap = TASK_SIZE - address; ++ guard_addr = address + guard_gap; ++ *gap = guard_gap; ++ ++ return guard_addr; ++} ++ + int expand_stack(struct vm_area_struct *vma, unsigned long address) + { ++ unsigned long gap; ++ ++ address = expandable_stack_area(vma, address, &gap); ++ if (IS_ERR_VALUE(address)) ++ return -ENOMEM; ++ return expand_upwards(vma, address, gap); ++} ++ ++int stack_guard_area(struct vm_area_struct *vma, unsigned long address) ++{ + struct vm_area_struct *next; + +- address &= PAGE_MASK; ++ if (!(vma->vm_flags & VM_GROWSUP)) ++ return 0; ++ ++ /* ++ * strictly speaking there is a guard gap between disjoint stacks ++ * but the gap is not canonical (it might be smaller) and it is ++ * reasonably safe to assume that we can ignore that gap for stack ++ * POPULATE or /proc/[s]maps purposes ++ */ + next = vma->vm_next; +- if (next && next->vm_start == address + PAGE_SIZE) { +- if (!(next->vm_flags & VM_GROWSUP)) +- return -ENOMEM; +- } +- return expand_upwards(vma, address); ++ if (next && next->vm_flags & VM_GROWSUP) ++ return 0; ++ ++ return vma->vm_end - address <= stack_guard_gap; + } + + struct vm_area_struct * +@@ -1939,17 +1991,73 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) + return prev; + } + #else ++unsigned long expandable_stack_area(struct vm_area_struct *vma, ++ unsigned long address, unsigned long *gap) ++{ ++ struct vm_area_struct *prev = vma->vm_prev; ++ unsigned long guard_gap = stack_guard_gap; ++ unsigned long guard_addr; ++ ++ address &= PAGE_MASK; ++ if (!prev) ++ goto out; ++ ++ /* ++ * Is there a mapping abutting this one below? ++ * ++ * That's only ok if it's the same stack mapping ++ * that has gotten split or there is sufficient gap ++ * between mappings ++ */ ++ if (prev->vm_flags & VM_GROWSDOWN) { ++ guard_gap = min(guard_gap, address - prev->vm_end); ++ goto out; ++ } ++ ++ if (address - prev->vm_end < guard_gap) ++ return -ENOMEM; ++ ++out: ++ /* make sure we won't underflow */ ++ if (address < mmap_min_addr) ++ return -ENOMEM; ++ if (address - mmap_min_addr < guard_gap) ++ guard_gap = address - mmap_min_addr; ++ ++ guard_addr = address - guard_gap; ++ *gap = guard_gap; ++ ++ return guard_addr; ++} ++ + int expand_stack(struct vm_area_struct *vma, unsigned long address) + { ++ unsigned long gap; ++ ++ address = expandable_stack_area(vma, address, &gap); ++ if (IS_ERR_VALUE(address)) ++ return -ENOMEM; ++ return expand_downwards(vma, address, gap); ++} ++ ++int stack_guard_area(struct vm_area_struct *vma, unsigned long address) ++{ + struct vm_area_struct *prev; + +- address &= PAGE_MASK; ++ if (!(vma->vm_flags & VM_GROWSDOWN)) ++ return 0; ++ ++ /* ++ * strictly speaking there is a guard gap between disjoint stacks ++ * but the gap is not canonical (it might be smaller) and it is ++ * reasonably safe to assume that we can ignore that gap for stack ++ * POPULATE or /proc/[s]maps purposes ++ */ + prev = vma->vm_prev; +- if (prev && prev->vm_end == address) { +- if (!(prev->vm_flags & VM_GROWSDOWN)) +- return -ENOMEM; +- } +- return expand_downwards(vma, address); ++ if (prev && prev->vm_flags & VM_GROWSDOWN) ++ return 0; ++ ++ return address - vma->vm_start < stack_guard_gap; + } + + struct vm_area_struct * +-- +1.8.5.2.233.g932f7e4 + diff --git a/recipes-kernel/linux/linux-windriver/0002-mm-proc-cap-the-stack-gap-for-unpopulated-growing-vm.patch b/recipes-kernel/linux/linux-windriver/0002-mm-proc-cap-the-stack-gap-for-unpopulated-growing-vm.patch new file mode 100644 index 0000000..a99b388 --- /dev/null +++ b/recipes-kernel/linux/linux-windriver/0002-mm-proc-cap-the-stack-gap-for-unpopulated-growing-vm.patch @@ -0,0 +1,54 @@ +From 1e1f5826c3e00927c16e8946459d68b1ffd22b64 Mon Sep 17 00:00:00 2001 +From: Michal Hocko +Date: Wed, 14 Jun 2017 08:17:15 +0200 +Subject: [PATCH 2/4] mm, proc: cap the stack gap for unpopulated growing vmas + +Oleg has noticed that show_map_vma has been overly eager to cut the +the vma range for growing VMAs. This wasn't a big deal with 4kB stack +gap but now that the gap is much larger we can simply get a bogus VMA +range in show_map_vma. + +To quote Oleg: + + "On ppc PAGE_SIZE == 64K, so stack_guard_gap == 16M, the application + does mmap(..., length=4M, ... MAP_GROWSDOWN) and /proc/pid/maps + happily reports + + 30001000000-30000400000 rw-p 00000000 00:00 0" + +Let's cap the reported range and show an empty range for this peculiar +case which is what we have been doing for a long time. Note that the +range will expand as soon as the first page fault happens on this range. + +Reported-by: Jan Stancek +Signed-off-by: Michal Hocko +Tested-by: Tony Luck # ia64 +Tested-by: Laura Abbott +Tested-by: Helge Deller # parisc +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +Signed-off-by: Zhang Xiao +--- + fs/proc/task_mmu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index f2bae95..1188b9e 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -236,10 +236,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + end = vma->vm_end; + if (vma->vm_flags & VM_GROWSDOWN) { + if (stack_guard_area(vma, start)) +- start += stack_guard_gap; ++ start = min(end, start + stack_guard_gap); + } else if (vma->vm_flags & VM_GROWSUP) { + if (stack_guard_area(vma, end)) +- end -= stack_guard_gap; ++ end = max(start, end - stack_guard_gap); + } + + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", +-- +1.8.5.2.233.g932f7e4 + diff --git a/recipes-kernel/linux/linux-windriver/0003-mm-allow-to-configure-stack-gap-size.patch b/recipes-kernel/linux/linux-windriver/0003-mm-allow-to-configure-stack-gap-size.patch new file mode 100644 index 0000000..385e9f2 --- /dev/null +++ b/recipes-kernel/linux/linux-windriver/0003-mm-allow-to-configure-stack-gap-size.patch @@ -0,0 +1,143 @@ +From 4d7b90282cf96870f7a97a4fac0634be43523e88 Mon Sep 17 00:00:00 2001 +From: Michal Hocko +Date: Fri, 16 Jun 2017 12:58:33 +0200 +Subject: [PATCH 3/4] mm: allow to configure stack gap size + +Add a kernel command line option (stack_guard_gap) to specify the stack +gap size (in page unites) and export the value in /proc//smaps for +stack vmas. This might be used for special applications like CRIU/RR. + +Changes since v1 + - do not rely on is_stack when reporting the gap. show_map_vma has all + the information we need + +Suggested-by: Linus Torvalds +Signed-off-by: Michal Hocko +Tested-by: Tony Luck # ia64 +Tested-by: Laura Abbott +Tested-by: Helge Deller # parisc +Signed-off-by: Linus Torvalds +[wt: backport to 4.9 : kernel-parameters.txt is in Documentation/] +[wt: backport to 3.10 : adjust context] +Signed-off-by: Willy Tarreau +Signed-off-by: Zhang Xiao +--- + Documentation/kernel-parameters.txt | 7 +++++++ + fs/proc/task_mmu.c | 20 +++++++++++++++----- + mm/mmap.c | 13 +++++++++++++ + 3 files changed, 35 insertions(+), 5 deletions(-) + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index a4db1f0..309601c 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -2562,6 +2562,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. + spia_pedr= + spia_peddr= + ++ stack_guard_gap= ++ [MM] override the default stack gap protection.The ++ value is in page units and it defines how many pages ++ prior to (for stacks growing down) resp. after (for ++ stacks growing up) the main stack are reserved for no ++ other mapping. Default value is 256 pages. ++ + stacktrace [FTRACE] + Enabled the stack tracer on boot up. + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 1188b9e..959c864 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -210,7 +210,7 @@ static int do_maps_open(struct inode *inode, struct file *file, + } + + static void +-show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) ++show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid, bool *has_gap) + { + struct mm_struct *mm = vma->vm_mm; + struct file *file = vma->vm_file; +@@ -235,11 +235,17 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + start = vma->vm_start; + end = vma->vm_end; + if (vma->vm_flags & VM_GROWSDOWN) { +- if (stack_guard_area(vma, start)) ++ if (stack_guard_area(vma, start)) { + start = min(end, start + stack_guard_gap); ++ if (has_gap) ++ *has_gap = true; ++ } + } else if (vma->vm_flags & VM_GROWSUP) { +- if (stack_guard_area(vma, end)) ++ if (stack_guard_area(vma, end)) { + end = max(start, end - stack_guard_gap); ++ if (has_gap) ++ *has_gap = true; ++ } + } + + seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", +@@ -309,7 +315,7 @@ static int show_map(struct seq_file *m, void *v, int is_pid) + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; + +- show_map_vma(m, vma, is_pid); ++ show_map_vma(m, vma, is_pid, NULL); + + if (m->count < m->size) /* vma is copied successfully */ + m->version = (vma != get_gate_vma(task->mm)) +@@ -484,6 +490,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) + .mm = vma->vm_mm, + .private = &mss, + }; ++ bool has_gap = false; + + memset(&mss, 0, sizeof mss); + mss.vma = vma; +@@ -491,7 +498,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) + if (vma->vm_mm && !is_vm_hugetlb_page(vma)) + walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); + +- show_map_vma(m, vma, is_pid); ++ show_map_vma(m, vma, is_pid, &has_gap); + + seq_printf(m, + "Size: %8lu kB\n" +@@ -524,6 +531,9 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) + (vma->vm_flags & VM_LOCKED) ? + (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); + ++ if (has_gap) ++ seq_printf(m, "Stack_Gap: %8lu kB\n", stack_guard_gap >>10); ++ + if (m->count < m->size) /* vma is copied successfully */ + m->version = (vma != get_gate_vma(task->mm)) + ? vma->vm_start : 0; +diff --git a/mm/mmap.c b/mm/mmap.c +index 56cf13f..ce64e05 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -1904,6 +1904,19 @@ int expand_downwards(struct vm_area_struct *vma, + /* enforced gap between the expanding stack and other mappings. */ + unsigned long stack_guard_gap = 256UL<