|
@@ -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));
|