Skip to content

Commit

Permalink
kasan: add proper page allocator tests
Browse files Browse the repository at this point in the history
The currently existing page allocator tests rely on kmalloc fallback
with large sizes that is only present for SLUB. Add proper tests that
use alloc/free_pages().

Link: https://linux-review.googlesource.com/id/Ia173d5a1b215fe6b2548d814ef0f4433cf983570
Link: https://lkml.kernel.org/r/a2648930e55ff75b8e700f2e0d905c2b55a67483.1610733117.git.andreyknvl@google.com
Signed-off-by: Andrey Konovalov <[email protected]>
Reviewed-by: Marco Elver <[email protected]>
Reviewed-by: 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]>
  • Loading branch information
xairy authored and torvalds committed Feb 24, 2021
1 parent 611806b commit 858bdeb
Showing 1 changed file with 46 additions and 5 deletions.
51 changes: 46 additions & 5 deletions lib/test_kasan.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,24 @@ static void kmalloc_node_oob_right(struct kunit *test)
kfree(ptr);
}

/*
* These kmalloc_pagealloc_* tests try allocating a memory chunk that doesn't
* fit into a slab cache and therefore is allocated via the page allocator
* fallback. Since this kind of fallback is only implemented for SLUB, these
* tests are limited to that allocator.
*/
static void kmalloc_pagealloc_oob_right(struct kunit *test)
{
char *ptr;
size_t size = KMALLOC_MAX_CACHE_SIZE + 10;

KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);

/*
* Allocate a chunk that does not fit into a SLUB cache to trigger
* the page allocator fallback.
*/
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);

KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + OOB_TAG_OFF] = 0);

kfree(ptr);
}

Expand All @@ -174,8 +177,8 @@ static void kmalloc_pagealloc_uaf(struct kunit *test)

ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);

kfree(ptr);

KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = 0);
}

Expand All @@ -192,6 +195,42 @@ static void kmalloc_pagealloc_invalid_free(struct kunit *test)
KUNIT_EXPECT_KASAN_FAIL(test, kfree(ptr + 1));
}

static void pagealloc_oob_right(struct kunit *test)
{
char *ptr;
struct page *pages;
size_t order = 4;
size_t size = (1UL << (PAGE_SHIFT + order));

/*
* With generic KASAN page allocations have no redzones, thus
* out-of-bounds detection is not guaranteed.
* See https://bugzilla.kernel.org/show_bug.cgi?id=210503.
*/
KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);

pages = alloc_pages(GFP_KERNEL, order);
ptr = page_address(pages);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);

KUNIT_EXPECT_KASAN_FAIL(test, ptr[size] = 0);
free_pages((unsigned long)ptr, order);
}

static void pagealloc_uaf(struct kunit *test)
{
char *ptr;
struct page *pages;
size_t order = 4;

pages = alloc_pages(GFP_KERNEL, order);
ptr = page_address(pages);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
free_pages((unsigned long)ptr, order);

KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = 0);
}

static void kmalloc_large_oob_right(struct kunit *test)
{
char *ptr;
Expand Down Expand Up @@ -903,6 +942,8 @@ static struct kunit_case kasan_kunit_test_cases[] = {
KUNIT_CASE(kmalloc_pagealloc_oob_right),
KUNIT_CASE(kmalloc_pagealloc_uaf),
KUNIT_CASE(kmalloc_pagealloc_invalid_free),
KUNIT_CASE(pagealloc_oob_right),
KUNIT_CASE(pagealloc_uaf),
KUNIT_CASE(kmalloc_large_oob_right),
KUNIT_CASE(kmalloc_oob_krealloc_more),
KUNIT_CASE(kmalloc_oob_krealloc_less),
Expand Down

0 comments on commit 858bdeb

Please sign in to comment.