summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-01-06 13:00:05 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-16 06:59:03 -0800
commit88b5d12c6413c7b80c3df4527b09c9d5f65c1c0a (patch)
tree3cd5283c6e9cf9704095d4ecf0f55f111805cfce
parent6bb148fb1e6a1211c55f8cc3fcd789c34483c7bb (diff)
downloadlinux-stable-88b5d12c6413c7b80c3df4527b09c9d5f65c1c0a.tar.gz
linux-stable-88b5d12c6413c7b80c3df4527b09c9d5f65c1c0a.tar.bz2
linux-stable-88b5d12c6413c7b80c3df4527b09c9d5f65c1c0a.zip
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>
-rw-r--r--include/linux/mm.h2
-rw-r--r--mm/memory.c4
2 files changed, 3 insertions, 3 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index d4cdac903468..c4085192c2b6 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1630,7 +1630,7 @@ extern int expand_downwards(struct vm_area_struct *vma,
#if VM_GROWSUP
extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
#else
- #define expand_upwards(vma, address) do { } while (0)
+ #define expand_upwards(vma, address) (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 0926ccd04d7a..8b2d75f61b32 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3200,7 +3200,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
if (prev && prev->vm_end == address)
return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
- expand_downwards(vma, address - PAGE_SIZE);
+ return 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;
@@ -3209,7 +3209,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
if (next && next->vm_start == address + PAGE_SIZE)
return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
- expand_upwards(vma, address + PAGE_SIZE);
+ return expand_upwards(vma, address + PAGE_SIZE);
}
return 0;
}