Skip to content

Commit 1dfbe9f

Browse files
Matthew Wilcox (Oracle)kees
authored andcommitted
usercopy: Make usercopy resilient against ridiculously large copies
If 'n' is so large that it's negative, we might wrap around and mistakenly think that the copy is OK when it's not. Such a copy would probably crash, but just doing the arithmetic in a more simple way lets us detect and refuse this case. Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Reviewed-by: Uladzislau Rezki (Sony) <[email protected]> Tested-by: Zorro Lang <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 35fb9ae commit 1dfbe9f

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

mm/usercopy.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,27 +162,26 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
162162
bool to_user)
163163
{
164164
uintptr_t addr = (uintptr_t)ptr;
165+
unsigned long offset;
165166
struct folio *folio;
166167

167168
if (is_kmap_addr(ptr)) {
168-
unsigned long page_end = addr | (PAGE_SIZE - 1);
169-
170-
if (addr + n - 1 > page_end)
171-
usercopy_abort("kmap", NULL, to_user,
172-
offset_in_page(ptr), n);
169+
offset = offset_in_page(ptr);
170+
if (n > PAGE_SIZE - offset)
171+
usercopy_abort("kmap", NULL, to_user, offset, n);
173172
return;
174173
}
175174

176175
if (is_vmalloc_addr(ptr)) {
177176
struct vmap_area *area = find_vmap_area(addr);
178-
unsigned long offset;
179177

180178
if (!area)
181179
usercopy_abort("vmalloc", "no area", to_user, 0, n);
182180

183-
offset = addr - area->va_start;
184-
if (addr + n > area->va_end)
181+
if (n > area->va_end - addr) {
182+
offset = addr - area->va_start;
185183
usercopy_abort("vmalloc", NULL, to_user, offset, n);
184+
}
186185
return;
187186
}
188187

@@ -195,8 +194,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
195194
/* Check slab allocator for flags and size. */
196195
__check_heap_object(ptr, n, folio_slab(folio), to_user);
197196
} else if (folio_test_large(folio)) {
198-
unsigned long offset = ptr - folio_address(folio);
199-
if (offset + n > folio_size(folio))
197+
offset = ptr - folio_address(folio);
198+
if (n > folio_size(folio) - offset)
200199
usercopy_abort("page alloc", NULL, to_user, offset, n);
201200
}
202201
}

0 commit comments

Comments
 (0)