1 // SPDX-License-Identifier: GPL-2.0 2 #include <kunit/test.h> 3 #include <linux/mm.h> 4 #include <linux/slab.h> 5 #include <linux/module.h> 6 #include <linux/kernel.h> 7 #include "../mm/slab.h" 8 9 static struct kunit_resource resource; 10 static int slab_errors; 11 12 /* 13 * Wrapper function for kmem_cache_create(), which reduces 2 parameters: 14 * 'align' and 'ctor', and sets SLAB_SKIP_KFENCE flag to avoid getting an 15 * object from kfence pool, where the operation could be caught by both 16 * our test and kfence sanity check. 17 */ 18 static struct kmem_cache *test_kmem_cache_create(const char *name, 19 unsigned int size, slab_flags_t flags) 20 { 21 struct kmem_cache *s = kmem_cache_create(name, size, 0, 22 (flags | SLAB_NO_USER_FLAGS), NULL); 23 s->flags |= SLAB_SKIP_KFENCE; 24 return s; 25 } 26 27 static void test_clobber_zone(struct kunit *test) 28 { 29 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_alloc", 64, 30 SLAB_RED_ZONE); 31 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 32 33 kasan_disable_current(); 34 p[64] = 0x12; 35 36 validate_slab_cache(s); 37 KUNIT_EXPECT_EQ(test, 2, slab_errors); 38 39 kasan_enable_current(); 40 kmem_cache_free(s, p); 41 kmem_cache_destroy(s); 42 } 43 44 #ifndef CONFIG_KASAN 45 static void test_next_pointer(struct kunit *test) 46 { 47 struct kmem_cache *s = test_kmem_cache_create("TestSlub_next_ptr_free", 48 64, SLAB_POISON); 49 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 50 unsigned long tmp; 51 unsigned long *ptr_addr; 52 53 kmem_cache_free(s, p); 54 55 ptr_addr = (unsigned long *)(p + s->offset); 56 tmp = *ptr_addr; 57 p[s->offset] = 0x12; 58 59 /* 60 * Expecting three errors. 61 * One for the corrupted freechain and the other one for the wrong 62 * count of objects in use. The third error is fixing broken cache. 63 */ 64 validate_slab_cache(s); 65 KUNIT_EXPECT_EQ(test, 3, slab_errors); 66 67 /* 68 * Try to repair corrupted freepointer. 69 * Still expecting two errors. The first for the wrong count 70 * of objects in use. 71 * The second error is for fixing broken cache. 72 */ 73 *ptr_addr = tmp; 74 slab_errors = 0; 75 76 validate_slab_cache(s); 77 KUNIT_EXPECT_EQ(test, 2, slab_errors); 78 79 /* 80 * Previous validation repaired the count of objects in use. 81 * Now expecting no error. 82 */ 83 slab_errors = 0; 84 validate_slab_cache(s); 85 KUNIT_EXPECT_EQ(test, 0, slab_errors); 86 87 kmem_cache_destroy(s); 88 } 89 90 static void test_first_word(struct kunit *test) 91 { 92 struct kmem_cache *s = test_kmem_cache_create("TestSlub_1th_word_free", 93 64, SLAB_POISON); 94 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 95 96 kmem_cache_free(s, p); 97 *p = 0x78; 98 99 validate_slab_cache(s); 100 KUNIT_EXPECT_EQ(test, 2, slab_errors); 101 102 kmem_cache_destroy(s); 103 } 104 105 static void test_clobber_50th_byte(struct kunit *test) 106 { 107 struct kmem_cache *s = test_kmem_cache_create("TestSlub_50th_word_free", 108 64, SLAB_POISON); 109 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 110 111 kmem_cache_free(s, p); 112 p[50] = 0x9a; 113 114 validate_slab_cache(s); 115 KUNIT_EXPECT_EQ(test, 2, slab_errors); 116 117 kmem_cache_destroy(s); 118 } 119 #endif 120 121 static void test_clobber_redzone_free(struct kunit *test) 122 { 123 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_free", 64, 124 SLAB_RED_ZONE); 125 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 126 127 kasan_disable_current(); 128 kmem_cache_free(s, p); 129 p[64] = 0xab; 130 131 validate_slab_cache(s); 132 KUNIT_EXPECT_EQ(test, 2, slab_errors); 133 134 kasan_enable_current(); 135 kmem_cache_destroy(s); 136 } 137 138 static void test_kmalloc_redzone_access(struct kunit *test) 139 { 140 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_kmalloc", 32, 141 SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE); 142 u8 *p = kmalloc_trace(s, GFP_KERNEL, 18); 143 144 kasan_disable_current(); 145 146 /* Suppress the -Warray-bounds warning */ 147 OPTIMIZER_HIDE_VAR(p); 148 p[18] = 0xab; 149 p[19] = 0xab; 150 151 validate_slab_cache(s); 152 KUNIT_EXPECT_EQ(test, 2, slab_errors); 153 154 kasan_enable_current(); 155 kmem_cache_free(s, p); 156 kmem_cache_destroy(s); 157 } 158 159 static int test_init(struct kunit *test) 160 { 161 slab_errors = 0; 162 163 kunit_add_named_resource(test, NULL, NULL, &resource, 164 "slab_errors", &slab_errors); 165 return 0; 166 } 167 168 static struct kunit_case test_cases[] = { 169 KUNIT_CASE(test_clobber_zone), 170 171 #ifndef CONFIG_KASAN 172 KUNIT_CASE(test_next_pointer), 173 KUNIT_CASE(test_first_word), 174 KUNIT_CASE(test_clobber_50th_byte), 175 #endif 176 177 KUNIT_CASE(test_clobber_redzone_free), 178 KUNIT_CASE(test_kmalloc_redzone_access), 179 {} 180 }; 181 182 static struct kunit_suite test_suite = { 183 .name = "slub_test", 184 .init = test_init, 185 .test_cases = test_cases, 186 }; 187 kunit_test_suite(test_suite); 188 189 MODULE_LICENSE("GPL"); 190