Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kasan: unify large kfree checks

Unify checks in kasan_kfree_large() and in kasan_slab_free_mempool() for
large allocations as it's done for small kfree() allocations.

With this change, kasan_slab_free_mempool() starts checking that the first
byte of the memory that's being freed is accessible.

Link: https://lkml.kernel.org/r/14ffc4cd867e0b1ed58f7527e3b748a1b4ad08aa.1612546384.git.andreyknvl@google.com
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Reviewed-by: Marco Elver <elver@google.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Branislav Rankov <Branislav.Rankov@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Evgenii Stepanov <eugenis@google.com>
Cc: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: Peter Collingbourne <pcc@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrey Konovalov and committed by
Linus Torvalds
200072ce df54b383

+34 -18
+8 -8
include/linux/kasan.h
··· 200 200 return false; 201 201 } 202 202 203 + void __kasan_kfree_large(void *ptr, unsigned long ip); 204 + static __always_inline void kasan_kfree_large(void *ptr) 205 + { 206 + if (kasan_enabled()) 207 + __kasan_kfree_large(ptr, _RET_IP_); 208 + } 209 + 203 210 void __kasan_slab_free_mempool(void *ptr, unsigned long ip); 204 211 static __always_inline void kasan_slab_free_mempool(void *ptr) 205 212 { ··· 252 245 if (kasan_enabled()) 253 246 return __kasan_krealloc(object, new_size, flags); 254 247 return (void *)object; 255 - } 256 - 257 - void __kasan_kfree_large(void *ptr, unsigned long ip); 258 - static __always_inline void kasan_kfree_large(void *ptr) 259 - { 260 - if (kasan_enabled()) 261 - __kasan_kfree_large(ptr, _RET_IP_); 262 248 } 263 249 264 250 /* ··· 302 302 { 303 303 return false; 304 304 } 305 + static inline void kasan_kfree_large(void *ptr) {} 305 306 static inline void kasan_slab_free_mempool(void *ptr) {} 306 307 static inline void *kasan_slab_alloc(struct kmem_cache *s, void *object, 307 308 gfp_t flags) ··· 323 322 { 324 323 return (void *)object; 325 324 } 326 - static inline void kasan_kfree_large(void *ptr) {} 327 325 static inline bool kasan_check_byte(const void *address) 328 326 { 329 327 return true;
+26 -10
mm/kasan/common.c
··· 364 364 return ____kasan_slab_free(cache, object, ip, true); 365 365 } 366 366 367 + static bool ____kasan_kfree_large(void *ptr, unsigned long ip) 368 + { 369 + if (ptr != page_address(virt_to_head_page(ptr))) { 370 + kasan_report_invalid_free(ptr, ip); 371 + return true; 372 + } 373 + 374 + if (!kasan_byte_accessible(ptr)) { 375 + kasan_report_invalid_free(ptr, ip); 376 + return true; 377 + } 378 + 379 + /* 380 + * The object will be poisoned by kasan_free_pages() or 381 + * kasan_slab_free_mempool(). 382 + */ 383 + 384 + return false; 385 + } 386 + 387 + void __kasan_kfree_large(void *ptr, unsigned long ip) 388 + { 389 + ____kasan_kfree_large(ptr, ip); 390 + } 391 + 367 392 void __kasan_slab_free_mempool(void *ptr, unsigned long ip) 368 393 { 369 394 struct page *page; ··· 402 377 * KMALLOC_MAX_SIZE, and kmalloc falls back onto page_alloc. 403 378 */ 404 379 if (unlikely(!PageSlab(page))) { 405 - if (ptr != page_address(page)) { 406 - kasan_report_invalid_free(ptr, ip); 380 + if (____kasan_kfree_large(ptr, ip)) 407 381 return; 408 - } 409 382 kasan_poison(ptr, page_size(page), KASAN_FREE_PAGE); 410 383 } else { 411 384 ____kasan_slab_free(page->slab_cache, ptr, ip, false); ··· 560 537 return __kasan_kmalloc_large(object, size, flags); 561 538 else 562 539 return ____kasan_kmalloc(page->slab_cache, object, size, flags); 563 - } 564 - 565 - void __kasan_kfree_large(void *ptr, unsigned long ip) 566 - { 567 - if (ptr != page_address(virt_to_head_page(ptr))) 568 - kasan_report_invalid_free(ptr, ip); 569 - /* The object will be poisoned by kasan_free_pages(). */ 570 540 } 571 541 572 542 bool __kasan_check_byte(const void *address, unsigned long ip)