Skip to content

Commit 200072c

Browse files
xairytorvalds
authored andcommitted
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 <[email protected]> Reviewed-by: Marco Elver <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Andrey Ryabinin <[email protected]> Cc: Branislav Rankov <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Evgenii Stepanov <[email protected]> Cc: Kevin Brodsky <[email protected]> Cc: Peter Collingbourne <[email protected]> Cc: Vincenzo Frascino <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent df54b38 commit 200072c

2 files changed

Lines changed: 34 additions & 18 deletions

File tree

include/linux/kasan.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ static __always_inline bool kasan_slab_free(struct kmem_cache *s, void *object)
200200
return false;
201201
}
202202

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+
203210
void __kasan_slab_free_mempool(void *ptr, unsigned long ip);
204211
static __always_inline void kasan_slab_free_mempool(void *ptr)
205212
{
@@ -247,13 +254,6 @@ static __always_inline void * __must_check kasan_krealloc(const void *object,
247254
return (void *)object;
248255
}
249256

250-
void __kasan_kfree_large(void *ptr, unsigned long ip);
251-
static __always_inline void kasan_kfree_large(void *ptr)
252-
{
253-
if (kasan_enabled())
254-
__kasan_kfree_large(ptr, _RET_IP_);
255-
}
256-
257257
/*
258258
* Unlike kasan_check_read/write(), kasan_check_byte() is performed even for
259259
* the hardware tag-based mode that doesn't rely on compiler instrumentation.
@@ -302,6 +302,7 @@ static inline bool kasan_slab_free(struct kmem_cache *s, void *object)
302302
{
303303
return false;
304304
}
305+
static inline void kasan_kfree_large(void *ptr) {}
305306
static inline void kasan_slab_free_mempool(void *ptr) {}
306307
static inline void *kasan_slab_alloc(struct kmem_cache *s, void *object,
307308
gfp_t flags)
@@ -322,7 +323,6 @@ static inline void *kasan_krealloc(const void *object, size_t new_size,
322323
{
323324
return (void *)object;
324325
}
325-
static inline void kasan_kfree_large(void *ptr) {}
326326
static inline bool kasan_check_byte(const void *address)
327327
{
328328
return true;

mm/kasan/common.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,31 @@ bool __kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip)
364364
return ____kasan_slab_free(cache, object, ip, true);
365365
}
366366

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+
367392
void __kasan_slab_free_mempool(void *ptr, unsigned long ip)
368393
{
369394
struct page *page;
@@ -377,10 +402,8 @@ void __kasan_slab_free_mempool(void *ptr, unsigned long ip)
377402
* KMALLOC_MAX_SIZE, and kmalloc falls back onto page_alloc.
378403
*/
379404
if (unlikely(!PageSlab(page))) {
380-
if (ptr != page_address(page)) {
381-
kasan_report_invalid_free(ptr, ip);
405+
if (____kasan_kfree_large(ptr, ip))
382406
return;
383-
}
384407
kasan_poison(ptr, page_size(page), KASAN_FREE_PAGE);
385408
} else {
386409
____kasan_slab_free(page->slab_cache, ptr, ip, false);
@@ -539,13 +562,6 @@ void * __must_check __kasan_krealloc(const void *object, size_t size, gfp_t flag
539562
return ____kasan_kmalloc(page->slab_cache, object, size, flags);
540563
}
541564

542-
void __kasan_kfree_large(void *ptr, unsigned long ip)
543-
{
544-
if (ptr != page_address(virt_to_head_page(ptr)))
545-
kasan_report_invalid_free(ptr, ip);
546-
/* The object will be poisoned by kasan_free_pages(). */
547-
}
548-
549565
bool __kasan_check_byte(const void *address, unsigned long ip)
550566
{
551567
if (!kasan_byte_accessible(address)) {

0 commit comments

Comments
 (0)