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: Keith Packard <keithp@keithp.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
2069601b3f
Коммит
320b2b8de1
23
mm/memory.c
23
mm/memory.c
|
@ -2759,6 +2759,26 @@ out_release:
|
|||
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,
|
||||
* 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,
|
|||
spinlock_t *ptl;
|
||||
pte_t entry;
|
||||
|
||||
if (check_stack_guard_page(vma, address) < 0)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (!(flags & FAULT_FLAG_WRITE)) {
|
||||
entry = pte_mkspecial(pfn_pte(my_zero_pfn(address),
|
||||
vma->vm_page_prot));
|
||||
|
|
Загрузка…
Ссылка в новой задаче