diff options
| author | Samuel Moelius <sam.moelius@trailofbits.com> | 2026-06-09 00:48:15 +0000 |
|---|---|---|
| committer | Andrew Morton <akpm@linux-foundation.org> | 2026-06-21 11:37:37 -0700 |
| commit | e8ae6fd67021fafa9205330b3b248c9fc7216e0b (patch) | |
| tree | d18bc7aa9bca4ef921df99dcaffce97736bc5898 /mm | |
| parent | 5419cac89c0224b5acdbcda183a3c4809510ce95 (diff) | |
| download | ath-e8ae6fd67021fafa9205330b3b248c9fc7216e0b.tar.gz | |
mm/gup_test: reject wrapped user ranges
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>
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/gup_test.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/mm/gup_test.c b/mm/gup_test.c index 9dd48db897b95..eb4c9cda16ed8 100644 --- a/mm/gup_test.c +++ b/mm/gup_test.c @@ -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; } |
