|
@@ -2185,9 +2185,28 @@ int expand_downwards(struct vm_area_struct *vma,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Note how expand_stack() refuses to expand the stack all the way to
|
|
|
+ * abut the next virtual mapping, *unless* that mapping itself is also
|
|
|
+ * a stack mapping. We want to leave room for a guard page, after all
|
|
|
+ * (the guard page itself is not added here, that is done by the
|
|
|
+ * actual page faulting logic)
|
|
|
+ *
|
|
|
+ * This matches the behavior of the guard page logic (see mm/memory.c:
|
|
|
+ * check_stack_guard_page()), which only allows the guard page to be
|
|
|
+ * removed under these circumstances.
|
|
|
+ */
|
|
|
#ifdef CONFIG_STACK_GROWSUP
|
|
|
int expand_stack(struct vm_area_struct *vma, unsigned long address)
|
|
|
{
|
|
|
+ struct vm_area_struct *next;
|
|
|
+
|
|
|
+ address &= PAGE_MASK;
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
@@ -2209,6 +2228,14 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr)
|
|
|
#else
|
|
|
int expand_stack(struct vm_area_struct *vma, unsigned long address)
|
|
|
{
|
|
|
+ struct vm_area_struct *prev;
|
|
|
+
|
|
|
+ address &= PAGE_MASK;
|
|
|
+ prev = vma->vm_prev;
|
|
|
+ if (prev && prev->vm_end == address) {
|
|
|
+ if (!(prev->vm_flags & VM_GROWSDOWN))
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
return expand_downwards(vma, address);
|
|
|
}
|
|
|
|