Skip to content

Commit 38931d8

Browse files
committed
mm: Make ksize() a reporting-only function
With all "silently resizing" callers of ksize() refactored, remove the logic in ksize() that would allow it to be used to effectively change the size of an allocation (bypassing __alloc_size hints, etc). Users wanting this feature need to either use kmalloc_size_roundup() before an allocation, or use krealloc() directly. For kfree_sensitive(), move the unpoisoning logic inline. Replace the some of the partially open-coded ksize() in __do_krealloc with ksize() now that it doesn't perform unpoisoning. Adjust the KUnit tests to match the new ksize() behavior. Execution tested with: $ ./tools/testing/kunit/kunit.py run \ --kconfig_add CONFIG_KASAN=y \ --kconfig_add CONFIG_KASAN_GENERIC=y \ --arch x86_64 kasan Cc: Christoph Lameter <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Joonsoo Kim <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Hyeonggon Yoo <[email protected]> Cc: Andrey Ryabinin <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Vincenzo Frascino <[email protected]> Cc: [email protected] Cc: [email protected] Acked-by: Vlastimil Babka <[email protected]> Acked-by: David Rientjes <[email protected]> Enhanced-by: Andrey Konovalov <[email protected]> Signed-off-by: Kees Cook <[email protected]>
1 parent 9124a26 commit 38931d8

File tree

2 files changed

+23
-22
lines changed

2 files changed

+23
-22
lines changed

mm/kasan/kasan_test.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -783,23 +783,30 @@ static void kasan_global_oob_left(struct kunit *test)
783783
KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
784784
}
785785

786-
/* Check that ksize() makes the whole object accessible. */
786+
/* Check that ksize() does NOT unpoison whole object. */
787787
static void ksize_unpoisons_memory(struct kunit *test)
788788
{
789789
char *ptr;
790-
size_t size = 123, real_size;
790+
size_t size = 128 - KASAN_GRANULE_SIZE - 5;
791+
size_t real_size;
791792

792793
ptr = kmalloc(size, GFP_KERNEL);
793794
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
795+
794796
real_size = ksize(ptr);
797+
KUNIT_EXPECT_GT(test, real_size, size);
795798

796799
OPTIMIZER_HIDE_VAR(ptr);
797800

798-
/* This access shouldn't trigger a KASAN report. */
799-
ptr[size] = 'x';
801+
/* These accesses shouldn't trigger a KASAN report. */
802+
ptr[0] = 'x';
803+
ptr[size - 1] = 'x';
800804

801-
/* This one must. */
802-
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[real_size]);
805+
/* These must trigger a KASAN report. */
806+
if (IS_ENABLED(CONFIG_KASAN_GENERIC))
807+
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]);
808+
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size + 5]);
809+
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[real_size - 1]);
803810

804811
kfree(ptr);
805812
}

mm/slab_common.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,11 +1333,11 @@ __do_krealloc(const void *p, size_t new_size, gfp_t flags)
13331333
void *ret;
13341334
size_t ks;
13351335

1336-
/* Don't use instrumented ksize to allow precise KASAN poisoning. */
1336+
/* Check for double-free before calling ksize. */
13371337
if (likely(!ZERO_OR_NULL_PTR(p))) {
13381338
if (!kasan_check_byte(p))
13391339
return NULL;
1340-
ks = kfence_ksize(p) ?: __ksize(p);
1340+
ks = ksize(p);
13411341
} else
13421342
ks = 0;
13431343

@@ -1405,8 +1405,10 @@ void kfree_sensitive(const void *p)
14051405
void *mem = (void *)p;
14061406

14071407
ks = ksize(mem);
1408-
if (ks)
1408+
if (ks) {
1409+
kasan_unpoison_range(mem, ks);
14091410
memzero_explicit(mem, ks);
1411+
}
14101412
kfree(mem);
14111413
}
14121414
EXPORT_SYMBOL(kfree_sensitive);
@@ -1427,13 +1429,11 @@ EXPORT_SYMBOL(kfree_sensitive);
14271429
*/
14281430
size_t ksize(const void *objp)
14291431
{
1430-
size_t size;
1431-
14321432
/*
1433-
* We need to first check that the pointer to the object is valid, and
1434-
* only then unpoison the memory. The report printed from ksize() is
1435-
* more useful, then when it's printed later when the behaviour could
1436-
* be undefined due to a potential use-after-free or double-free.
1433+
* We need to first check that the pointer to the object is valid.
1434+
* The KASAN report printed from ksize() is more useful, then when
1435+
* it's printed later when the behaviour could be undefined due to
1436+
* a potential use-after-free or double-free.
14371437
*
14381438
* We use kasan_check_byte(), which is supported for the hardware
14391439
* tag-based KASAN mode, unlike kasan_check_read/write().
@@ -1447,13 +1447,7 @@ size_t ksize(const void *objp)
14471447
if (unlikely(ZERO_OR_NULL_PTR(objp)) || !kasan_check_byte(objp))
14481448
return 0;
14491449

1450-
size = kfence_ksize(objp) ?: __ksize(objp);
1451-
/*
1452-
* We assume that ksize callers could use whole allocated area,
1453-
* so we need to unpoison this area.
1454-
*/
1455-
kasan_unpoison_range(objp, size);
1456-
return size;
1450+
return kfence_ksize(objp) ?: __ksize(objp);
14571451
}
14581452
EXPORT_SYMBOL(ksize);
14591453

0 commit comments

Comments
 (0)