]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gup: add warning if some caller would seem to want stack expansion
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 25 Jun 2023 21:02:25 +0000 (14:02 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 1 Jul 2023 11:14:46 +0000 (13:14 +0200)
commit a425ac5365f6cb3cc47bf83e6bff0213c10445f7 upstream.

It feels very unlikely that anybody would want to do a GUP in an
unmapped area under the stack pointer, but real users sometimes do some
really strange things.  So add a (temporary) warning for the case where
a GUP fails and expanding the stack might have made it work.

It's trivial to do the expansion in the caller as part of getting the mm
lock in the first place - see __access_remote_vm() for ptrace, for
example - it's just that it's unnecessarily painful to do it deep in the
guts of the GUP lookup when we might have to drop and re-take the lock.

I doubt anybody actually does anything quite this strange, but let's be
proactive: adding these warnings is simple, and will make debugging it
much easier if they trigger.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
mm/gup.c

index 6ffe51050b808c725b25a66da4d0b3a7538efcfd..eb0b96985c3c443f52e2875c5336100f68f1de3b 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1096,7 +1096,11 @@ static long __get_user_pages(struct mm_struct *mm,
 
                /* first iteration or cross vma bound */
                if (!vma || start >= vma->vm_end) {
-                       vma = vma_lookup(mm, start);
+                       vma = find_vma(mm, start);
+                       if (vma && (start < vma->vm_start)) {
+                               WARN_ON_ONCE(vma->vm_flags & VM_GROWSDOWN);
+                               vma = NULL;
+                       }
                        if (!vma && in_gate_area(mm, start)) {
                                ret = get_gate_page(mm, start & PAGE_MASK,
                                                gup_flags, &vma,
@@ -1265,9 +1269,13 @@ int fixup_user_fault(struct mm_struct *mm,
                fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
 retry:
-       vma = vma_lookup(mm, address);
+       vma = find_vma(mm, address);
        if (!vma)
                return -EFAULT;
+       if (address < vma->vm_start ) {
+               WARN_ON_ONCE(vma->vm_flags & VM_GROWSDOWN);
+               return -EFAULT;
+       }
 
        if (!vma_permits_fault(vma, fault_flags))
                return -EFAULT;