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, mm: fail krealloc on freed objects

Currently, if krealloc() is called on a freed object with KASAN enabled,
it allocates and returns a new object, but doesn't copy any memory from
the old one as ksize() returns 0. This makes the caller believe that
krealloc() succeeded (KASAN report is printed though).

This patch adds an accessibility check into __do_krealloc(). If the check
fails, krealloc() returns NULL. This check duplicates the one in ksize();
this is fixed in the following patch.

This patch also adds a KASAN-KUnit test to check krealloc() behaviour when
it's called on a freed object.

Link: https://lkml.kernel.org/r/cbcf7b02be0a1ca11de4f833f2ff0b3f2c9b00c8.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
26a5ca7a b87c28b9

+23
+20
lib/test_kasan.c
··· 353 353 KMALLOC_MAX_CACHE_SIZE + 201); 354 354 } 355 355 356 + /* 357 + * Check that krealloc() detects a use-after-free, returns NULL, 358 + * and doesn't unpoison the freed object. 359 + */ 360 + static void krealloc_uaf(struct kunit *test) 361 + { 362 + char *ptr1, *ptr2; 363 + int size1 = 201; 364 + int size2 = 235; 365 + 366 + ptr1 = kmalloc(size1, GFP_KERNEL); 367 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1); 368 + kfree(ptr1); 369 + 370 + KUNIT_EXPECT_KASAN_FAIL(test, ptr2 = krealloc(ptr1, size2, GFP_KERNEL)); 371 + KUNIT_ASSERT_PTR_EQ(test, (void *)ptr2, NULL); 372 + KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)ptr1); 373 + } 374 + 356 375 static void kmalloc_oob_16(struct kunit *test) 357 376 { 358 377 struct { ··· 1069 1050 KUNIT_CASE(krealloc_less_oob), 1070 1051 KUNIT_CASE(krealloc_pagealloc_more_oob), 1071 1052 KUNIT_CASE(krealloc_pagealloc_less_oob), 1053 + KUNIT_CASE(krealloc_uaf), 1072 1054 KUNIT_CASE(kmalloc_oob_16), 1073 1055 KUNIT_CASE(kmalloc_uaf_16), 1074 1056 KUNIT_CASE(kmalloc_oob_in_memset),
+3
mm/slab_common.c
··· 1136 1136 void *ret; 1137 1137 size_t ks; 1138 1138 1139 + if (likely(!ZERO_OR_NULL_PTR(p)) && !kasan_check_byte(p)) 1140 + return NULL; 1141 + 1139 1142 ks = ksize(p); 1140 1143 1141 1144 if (ks >= new_size) {