Commit c03aed64c4fc9e39e8727920971d889dac14b002

Authored by Linus Torvalds
Committed by Greg Kroah-Hartman
1 parent 53bcf5c328

mm: propagate error from stack expansion even for guard page

commit fee7e49d45149fba60156f5b59014f764d3e3728 upstream.

Jay Foad reports that the address sanitizer test (asan) sometimes gets
confused by a stack pointer that ends up being outside the stack vma
that is reported by /proc/maps.

This happens due to an interaction between RLIMIT_STACK and the guard
page: when we do the guard page check, we ignore the potential error
from the stack expansion, which effectively results in a missing guard
page, since the expected stack expansion won't have been done.

And since /proc/maps explicitly ignores the guard page (commit
d7824370e263: "mm: fix up some user-visible effects of the stack guard
page"), the stack pointer ends up being outside the reported stack area.

This is the minimal patch: it just propagates the error.  It also
effectively makes the guard page part of the stack limit, which in turn
measn that the actual real stack is one page less than the stack limit.

Let's see if anybody notices.  We could teach acct_stack_growth() to
allow an extra page for a grow-up/grow-down stack in the rlimit test,
but I don't want to add more complexity if it isn't needed.

Reported-and-tested-by: Jay Foad <jay.foad@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 2 changed files with 3 additions and 3 deletions Side-by-side Diff

... ... @@ -1936,7 +1936,7 @@
1936 1936 #if VM_GROWSUP
1937 1937 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
1938 1938 #else
1939   - #define expand_upwards(vma, address) do { } while (0)
  1939 + #define expand_upwards(vma, address) (0)
1940 1940 #endif
1941 1941  
1942 1942 /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
... ... @@ -2613,7 +2613,7 @@
2613 2613 if (prev && prev->vm_end == address)
2614 2614 return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
2615 2615  
2616   - expand_downwards(vma, address - PAGE_SIZE);
  2616 + return expand_downwards(vma, address - PAGE_SIZE);
2617 2617 }
2618 2618 if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
2619 2619 struct vm_area_struct *next = vma->vm_next;
... ... @@ -2622,7 +2622,7 @@
2622 2622 if (next && next->vm_start == address + PAGE_SIZE)
2623 2623 return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
2624 2624  
2625   - expand_upwards(vma, address + PAGE_SIZE);
  2625 + return expand_upwards(vma, address + PAGE_SIZE);
2626 2626 }
2627 2627 return 0;
2628 2628 }