Commit 320b2b8d authored by Linus Torvalds's avatar Linus Torvalds

mm: keep a guard page below a grow-down stack segment

This is a rather minimally invasive patch to solve the problem of the
user stack growing into a memory mapped area below it.  Whenever we fill
the first page of the stack segment, expand the segment down by one
page.

Now, admittedly some odd application might _want_ the stack to grow down
into the preceding memory mapping, and so we may at some point need to
make this a process tunable (some people might also want to have more
than a single page of guarding), but let's try the minimal approach
first.

Tested with trivial application that maps a single page just below the
stack, and then starts recursing.  Without this, we will get a SIGSEGV
_after_ the stack has smashed the mapping.  With this patch, we'll get a
nice SIGBUS just as the stack touches the page just above the mapping.
Requested-by: default avatarKeith Packard <keithp@keithp.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2069601b
...@@ -2759,6 +2759,26 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2759,6 +2759,26 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
return ret; return ret;
} }
/*
* This is like a special single-page "expand_downwards()",
* except we must first make sure that 'address-PAGE_SIZE'
* doesn't hit another vma.
*
* The "find_vma()" will do the right thing even if we wrap
*/
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) {
address -= PAGE_SIZE;
if (find_vma(vma->vm_mm, address) != vma)
return -ENOMEM;
expand_stack(vma, address);
}
return 0;
}
/* /*
* We enter with non-exclusive mmap_sem (to exclude vma changes, * We enter with non-exclusive mmap_sem (to exclude vma changes,
* but allow concurrent faults), and pte mapped but not yet locked. * but allow concurrent faults), and pte mapped but not yet locked.
...@@ -2772,6 +2792,9 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2772,6 +2792,9 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
spinlock_t *ptl; spinlock_t *ptl;
pte_t entry; pte_t entry;
if (check_stack_guard_page(vma, address) < 0)
return VM_FAULT_SIGBUS;
if (!(flags & FAULT_FLAG_WRITE)) { if (!(flags & FAULT_FLAG_WRITE)) {
entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), entry = pte_mkspecial(pfn_pte(my_zero_pfn(address),
vma->vm_page_prot)); vma->vm_page_prot));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment