]> Git Repo - linux.git/blobdiff - lib/test_kasan.c
Merge branch 'mlxsw-various-fixes'
[linux.git] / lib / test_kasan.c
index e59f185b807511cd98a3506ce5aa57ee461ef9af..25576303897bd1ab9400c0c0425657b042b63530 100644 (file)
@@ -47,6 +47,11 @@ static bool multishot;
  */
 static int kasan_test_init(struct kunit *test)
 {
+       if (!kasan_enabled()) {
+               kunit_err(test, "can't run KASAN tests with KASAN disabled");
+               return -1;
+       }
+
        multishot = kasan_save_enable_multi_shot();
        kasan_set_tagging_report_once(false);
        return 0;
@@ -147,6 +152,12 @@ 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;
@@ -154,14 +165,11 @@ static void kmalloc_pagealloc_oob_right(struct kunit *test)
 
        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);
 }
 
@@ -174,8 +182,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);
 }
 
@@ -192,6 +200,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;
@@ -440,10 +484,11 @@ static void kmem_cache_oob(struct kunit *test)
 {
        char *p;
        size_t size = 200;
-       struct kmem_cache *cache = kmem_cache_create("test_cache",
-                                               size, 0,
-                                               0, NULL);
+       struct kmem_cache *cache;
+
+       cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
+
        p = kmem_cache_alloc(cache, GFP_KERNEL);
        if (!p) {
                kunit_err(test, "Allocation failed: %s\n", __func__);
@@ -452,11 +497,12 @@ static void kmem_cache_oob(struct kunit *test)
        }
 
        KUNIT_EXPECT_KASAN_FAIL(test, *p = p[size + OOB_TAG_OFF]);
+
        kmem_cache_free(cache, p);
        kmem_cache_destroy(cache);
 }
 
-static void memcg_accounted_kmem_cache(struct kunit *test)
+static void kmem_cache_accounted(struct kunit *test)
 {
        int i;
        char *p;
@@ -483,6 +529,31 @@ free_cache:
        kmem_cache_destroy(cache);
 }
 
+static void kmem_cache_bulk(struct kunit *test)
+{
+       struct kmem_cache *cache;
+       size_t size = 200;
+       char *p[10];
+       bool ret;
+       int i;
+
+       cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
+
+       ret = kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p), (void **)&p);
+       if (!ret) {
+               kunit_err(test, "Allocation failed: %s\n", __func__);
+               kmem_cache_destroy(cache);
+               return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(p); i++)
+               p[i][0] = p[i][size - 1] = 42;
+
+       kmem_cache_free_bulk(cache, ARRAY_SIZE(p), (void **)&p);
+       kmem_cache_destroy(cache);
+}
+
 static char global_array[10];
 
 static void kasan_global_oob(struct kunit *test)
@@ -496,6 +567,7 @@ static void kasan_global_oob(struct kunit *test)
        KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
 }
 
+/* Check that ksize() makes the whole object accessible. */
 static void ksize_unpoisons_memory(struct kunit *test)
 {
        char *ptr;
@@ -514,6 +586,24 @@ static void ksize_unpoisons_memory(struct kunit *test)
        kfree(ptr);
 }
 
+/*
+ * Check that a use-after-free is detected by ksize() and via normal accesses
+ * after it.
+ */
+static void ksize_uaf(struct kunit *test)
+{
+       char *ptr;
+       int size = 128 - KASAN_GRANULE_SIZE;
+
+       ptr = kmalloc(size, GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
+       kfree(ptr);
+
+       KUNIT_EXPECT_KASAN_FAIL(test, ksize(ptr));
+       KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = *ptr);
+       KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = *(ptr + size));
+}
+
 static void kasan_stack_oob(struct kunit *test)
 {
        char stack_array[10];
@@ -884,6 +974,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),
@@ -901,12 +993,14 @@ static struct kunit_case kasan_kunit_test_cases[] = {
        KUNIT_CASE(kfree_via_page),
        KUNIT_CASE(kfree_via_phys),
        KUNIT_CASE(kmem_cache_oob),
-       KUNIT_CASE(memcg_accounted_kmem_cache),
+       KUNIT_CASE(kmem_cache_accounted),
+       KUNIT_CASE(kmem_cache_bulk),
        KUNIT_CASE(kasan_global_oob),
        KUNIT_CASE(kasan_stack_oob),
        KUNIT_CASE(kasan_alloca_oob_left),
        KUNIT_CASE(kasan_alloca_oob_right),
        KUNIT_CASE(ksize_unpoisons_memory),
+       KUNIT_CASE(ksize_uaf),
        KUNIT_CASE(kmem_cache_double_free),
        KUNIT_CASE(kmem_cache_invalid_free),
        KUNIT_CASE(kasan_memchr),
This page took 0.038145 seconds and 4 git commands to generate.