usercopy: Remove folio references from check_heap_object()

Use page_slab() instead of virt_to_folio() followed by folio_slab().
We do end up calling compound_head() twice for non-slab copies, but that
will not be a problem once we allocate memdescs separately.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: linux-hardening@vger.kernel.org
Link: https://patch.msgid.link/20251113000932.1589073-14-willy@infradead.org
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
This commit is contained in:
Matthew Wilcox (Oracle) 2025-11-13 00:09:27 +00:00 committed by Vlastimil Babka
parent 025f5b870b
commit 5934b1be8d
1 changed files with 16 additions and 8 deletions

View File

@ -164,7 +164,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
{ {
unsigned long addr = (unsigned long)ptr; unsigned long addr = (unsigned long)ptr;
unsigned long offset; unsigned long offset;
struct folio *folio; struct page *page;
struct slab *slab;
if (is_kmap_addr(ptr)) { if (is_kmap_addr(ptr)) {
offset = offset_in_page(ptr); offset = offset_in_page(ptr);
@ -189,16 +190,23 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
if (!virt_addr_valid(ptr)) if (!virt_addr_valid(ptr))
return; return;
folio = virt_to_folio(ptr); page = virt_to_page(ptr);
slab = page_slab(page);
if (folio_test_slab(folio)) { if (slab) {
/* Check slab allocator for flags and size. */ /* Check slab allocator for flags and size. */
__check_heap_object(ptr, n, folio_slab(folio), to_user); __check_heap_object(ptr, n, slab, to_user);
} else if (folio_test_large(folio)) { } else if (PageCompound(page)) {
offset = ptr - folio_address(folio); page = compound_head(page);
if (n > folio_size(folio) - offset) offset = ptr - page_address(page);
if (n > page_size(page) - offset)
usercopy_abort("page alloc", NULL, to_user, offset, n); usercopy_abort("page alloc", NULL, to_user, offset, n);
} }
/*
* We cannot check non-compound pages. They might be part of
* a large allocation, in which case crossing a page boundary
* is fine.
*/
} }
DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_HARDENED_USERCOPY_DEFAULT_ON, DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_HARDENED_USERCOPY_DEFAULT_ON,