]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mm/gup_test: reject wrapped user ranges
authorSamuel Moelius <sam.moelius@trailofbits.com>
Tue, 9 Jun 2026 00:48:15 +0000 (00:48 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 21 Jun 2026 18:37:37 +0000 (11:37 -0700)
gup_test accepts an address and size from the debugfs ioctl and repeatedly
compares against addr + size.  If that addition wraps, the loop can be
skipped and the ioctl returns success with size rewritten to zero.

Compute the end address once with overflow checking and use that checked
end for the loop bounds.

Assisted-by: Codex:gpt-5.5-cyber-preview
Link: https://lore.kernel.org/20260609004814.1240586.6294d614ac80.gup-test-range-end-wrap@trailofbits.com
Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Peter Xu <peterx@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/gup_test.c

index 9dd48db897b9518ee69bd81bbf8e376eec936087..eb4c9cda16ed8d6ec2467a96ba379409c84cda28 100644 (file)
@@ -105,11 +105,15 @@ static int __gup_test_ioctl(unsigned int cmd,
        unsigned long i, nr_pages, addr, next;
        long nr;
        struct page **pages;
+       unsigned long end;
        int ret = 0;
        bool needs_mmap_lock =
                cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
 
-       if (gup->size > ULONG_MAX)
+       if (gup->addr > ULONG_MAX || gup->size > ULONG_MAX)
+               return -EINVAL;
+       if (check_add_overflow((unsigned long)gup->addr,
+                              (unsigned long)gup->size, &end))
                return -EINVAL;
 
        nr_pages = gup->size / PAGE_SIZE;
@@ -125,13 +129,13 @@ static int __gup_test_ioctl(unsigned int cmd,
        i = 0;
        nr = gup->nr_pages_per_call;
        start_time = ktime_get();
-       for (addr = gup->addr; addr < gup->addr + gup->size; addr = next) {
+       for (addr = gup->addr; addr < end; addr = next) {
                if (nr != gup->nr_pages_per_call)
                        break;
 
                next = addr + nr * PAGE_SIZE;
-               if (next > gup->addr + gup->size) {
-                       next = gup->addr + gup->size;
+               if (next > end) {
+                       next = end;
                        nr = (next - addr) / PAGE_SIZE;
                }