at master 329 lines 7.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <kunit/test.h> 3#include <kunit/test-bug.h> 4#include <linux/mm.h> 5#include <linux/slab.h> 6#include <linux/module.h> 7#include <linux/kernel.h> 8#include <linux/rcupdate.h> 9#include <linux/delay.h> 10#include "../mm/slab.h" 11 12static struct kunit_resource resource; 13static int slab_errors; 14 15/* 16 * Wrapper function for kmem_cache_create(), which reduces 2 parameters: 17 * 'align' and 'ctor', and sets SLAB_SKIP_KFENCE flag to avoid getting an 18 * object from kfence pool, where the operation could be caught by both 19 * our test and kfence sanity check. 20 */ 21static struct kmem_cache *test_kmem_cache_create(const char *name, 22 unsigned int size, slab_flags_t flags) 23{ 24 struct kmem_cache *s = kmem_cache_create(name, size, 0, 25 (flags | SLAB_NO_USER_FLAGS), NULL); 26 s->flags |= SLAB_SKIP_KFENCE; 27 return s; 28} 29 30static void test_clobber_zone(struct kunit *test) 31{ 32 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_alloc", 64, 33 SLAB_RED_ZONE); 34 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 35 36 kasan_disable_current(); 37 p[64] = 0x12; 38 39 validate_slab_cache(s); 40 KUNIT_EXPECT_EQ(test, 2, slab_errors); 41 42 kasan_enable_current(); 43 kmem_cache_free(s, p); 44 kmem_cache_destroy(s); 45} 46 47#ifndef CONFIG_KASAN 48static void test_next_pointer(struct kunit *test) 49{ 50 struct kmem_cache *s = test_kmem_cache_create("TestSlub_next_ptr_free", 51 64, SLAB_POISON); 52 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 53 unsigned long tmp; 54 unsigned long *ptr_addr; 55 56 kmem_cache_free(s, p); 57 58 ptr_addr = (unsigned long *)(p + s->offset); 59 tmp = *ptr_addr; 60 p[s->offset] = ~p[s->offset]; 61 62 /* 63 * Expecting three errors. 64 * One for the corrupted freechain and the other one for the wrong 65 * count of objects in use. The third error is fixing broken cache. 66 */ 67 validate_slab_cache(s); 68 KUNIT_EXPECT_EQ(test, 3, slab_errors); 69 70 /* 71 * Try to repair corrupted freepointer. 72 * Still expecting two errors. The first for the wrong count 73 * of objects in use. 74 * The second error is for fixing broken cache. 75 */ 76 *ptr_addr = tmp; 77 slab_errors = 0; 78 79 validate_slab_cache(s); 80 KUNIT_EXPECT_EQ(test, 2, slab_errors); 81 82 /* 83 * Previous validation repaired the count of objects in use. 84 * Now expecting no error. 85 */ 86 slab_errors = 0; 87 validate_slab_cache(s); 88 KUNIT_EXPECT_EQ(test, 0, slab_errors); 89 90 kmem_cache_destroy(s); 91} 92 93static void test_first_word(struct kunit *test) 94{ 95 struct kmem_cache *s = test_kmem_cache_create("TestSlub_1th_word_free", 96 64, SLAB_POISON); 97 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 98 99 kmem_cache_free(s, p); 100 *p = 0x78; 101 102 validate_slab_cache(s); 103 KUNIT_EXPECT_EQ(test, 2, slab_errors); 104 105 kmem_cache_destroy(s); 106} 107 108static void test_clobber_50th_byte(struct kunit *test) 109{ 110 struct kmem_cache *s = test_kmem_cache_create("TestSlub_50th_word_free", 111 64, SLAB_POISON); 112 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 113 114 kmem_cache_free(s, p); 115 p[50] = 0x9a; 116 117 validate_slab_cache(s); 118 KUNIT_EXPECT_EQ(test, 2, slab_errors); 119 120 kmem_cache_destroy(s); 121} 122#endif 123 124static void test_clobber_redzone_free(struct kunit *test) 125{ 126 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_free", 64, 127 SLAB_RED_ZONE); 128 u8 *p = kmem_cache_alloc(s, GFP_KERNEL); 129 130 kasan_disable_current(); 131 kmem_cache_free(s, p); 132 p[64] = 0xab; 133 134 validate_slab_cache(s); 135 KUNIT_EXPECT_EQ(test, 2, slab_errors); 136 137 kasan_enable_current(); 138 kmem_cache_destroy(s); 139} 140 141static void test_kmalloc_redzone_access(struct kunit *test) 142{ 143 struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_kmalloc", 32, 144 SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE); 145 u8 *p = alloc_hooks(__kmalloc_cache_noprof(s, GFP_KERNEL, 18)); 146 147 kasan_disable_current(); 148 149 /* Suppress the -Warray-bounds warning */ 150 OPTIMIZER_HIDE_VAR(p); 151 p[18] = 0xab; 152 p[19] = 0xab; 153 154 validate_slab_cache(s); 155 KUNIT_EXPECT_EQ(test, 2, slab_errors); 156 157 kasan_enable_current(); 158 kmem_cache_free(s, p); 159 kmem_cache_destroy(s); 160} 161 162struct test_kfree_rcu_struct { 163 struct rcu_head rcu; 164}; 165 166static void test_kfree_rcu(struct kunit *test) 167{ 168 struct kmem_cache *s; 169 struct test_kfree_rcu_struct *p; 170 171 if (IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST)) 172 kunit_skip(test, "can't do kfree_rcu() when test is built-in"); 173 174 s = test_kmem_cache_create("TestSlub_kfree_rcu", 175 sizeof(struct test_kfree_rcu_struct), 176 SLAB_NO_MERGE); 177 p = kmem_cache_alloc(s, GFP_KERNEL); 178 179 kfree_rcu(p, rcu); 180 kmem_cache_destroy(s); 181 182 KUNIT_EXPECT_EQ(test, 0, slab_errors); 183} 184 185struct cache_destroy_work { 186 struct work_struct work; 187 struct kmem_cache *s; 188}; 189 190static void cache_destroy_workfn(struct work_struct *w) 191{ 192 struct cache_destroy_work *cdw; 193 194 cdw = container_of(w, struct cache_destroy_work, work); 195 kmem_cache_destroy(cdw->s); 196} 197 198#define KMEM_CACHE_DESTROY_NR 10 199 200static void test_kfree_rcu_wq_destroy(struct kunit *test) 201{ 202 struct test_kfree_rcu_struct *p; 203 struct cache_destroy_work cdw; 204 struct workqueue_struct *wq; 205 struct kmem_cache *s; 206 unsigned int delay; 207 int i; 208 209 if (IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST)) 210 kunit_skip(test, "can't do kfree_rcu() when test is built-in"); 211 212 INIT_WORK_ONSTACK(&cdw.work, cache_destroy_workfn); 213 wq = alloc_workqueue("test_kfree_rcu_destroy_wq", 214 WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 0); 215 216 if (!wq) 217 kunit_skip(test, "failed to alloc wq"); 218 219 for (i = 0; i < KMEM_CACHE_DESTROY_NR; i++) { 220 s = test_kmem_cache_create("TestSlub_kfree_rcu_wq_destroy", 221 sizeof(struct test_kfree_rcu_struct), 222 SLAB_NO_MERGE); 223 224 if (!s) 225 kunit_skip(test, "failed to create cache"); 226 227 delay = get_random_u8(); 228 p = kmem_cache_alloc(s, GFP_KERNEL); 229 kfree_rcu(p, rcu); 230 231 cdw.s = s; 232 233 msleep(delay); 234 queue_work(wq, &cdw.work); 235 flush_work(&cdw.work); 236 } 237 238 destroy_workqueue(wq); 239 KUNIT_EXPECT_EQ(test, 0, slab_errors); 240} 241 242static void test_leak_destroy(struct kunit *test) 243{ 244 struct kmem_cache *s = test_kmem_cache_create("TestSlub_leak_destroy", 245 64, SLAB_NO_MERGE); 246 kmem_cache_alloc(s, GFP_KERNEL); 247 248 kmem_cache_destroy(s); 249 250 KUNIT_EXPECT_EQ(test, 2, slab_errors); 251} 252 253static void test_krealloc_redzone_zeroing(struct kunit *test) 254{ 255 u8 *p; 256 int i; 257 struct kmem_cache *s = test_kmem_cache_create("TestSlub_krealloc", 64, 258 SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE); 259 260 p = alloc_hooks(__kmalloc_cache_noprof(s, GFP_KERNEL, 48)); 261 memset(p, 0xff, 48); 262 263 kasan_disable_current(); 264 OPTIMIZER_HIDE_VAR(p); 265 266 /* Test shrink */ 267 p = krealloc(p, 40, GFP_KERNEL | __GFP_ZERO); 268 for (i = 40; i < 64; i++) 269 KUNIT_EXPECT_EQ(test, p[i], SLUB_RED_ACTIVE); 270 271 /* Test grow within the same 64B kmalloc object */ 272 p = krealloc(p, 56, GFP_KERNEL | __GFP_ZERO); 273 for (i = 40; i < 56; i++) 274 KUNIT_EXPECT_EQ(test, p[i], 0); 275 for (i = 56; i < 64; i++) 276 KUNIT_EXPECT_EQ(test, p[i], SLUB_RED_ACTIVE); 277 278 validate_slab_cache(s); 279 KUNIT_EXPECT_EQ(test, 0, slab_errors); 280 281 memset(p, 0xff, 56); 282 /* Test grow with allocating a bigger 128B object */ 283 p = krealloc(p, 112, GFP_KERNEL | __GFP_ZERO); 284 for (i = 0; i < 56; i++) 285 KUNIT_EXPECT_EQ(test, p[i], 0xff); 286 for (i = 56; i < 112; i++) 287 KUNIT_EXPECT_EQ(test, p[i], 0); 288 289 kfree(p); 290 kasan_enable_current(); 291 kmem_cache_destroy(s); 292} 293 294static int test_init(struct kunit *test) 295{ 296 slab_errors = 0; 297 298 kunit_add_named_resource(test, NULL, NULL, &resource, 299 "slab_errors", &slab_errors); 300 return 0; 301} 302 303static struct kunit_case test_cases[] = { 304 KUNIT_CASE(test_clobber_zone), 305 306#ifndef CONFIG_KASAN 307 KUNIT_CASE(test_next_pointer), 308 KUNIT_CASE(test_first_word), 309 KUNIT_CASE(test_clobber_50th_byte), 310#endif 311 312 KUNIT_CASE(test_clobber_redzone_free), 313 KUNIT_CASE(test_kmalloc_redzone_access), 314 KUNIT_CASE(test_kfree_rcu), 315 KUNIT_CASE(test_kfree_rcu_wq_destroy), 316 KUNIT_CASE(test_leak_destroy), 317 KUNIT_CASE(test_krealloc_redzone_zeroing), 318 {} 319}; 320 321static struct kunit_suite test_suite = { 322 .name = "slub_test", 323 .init = test_init, 324 .test_cases = test_cases, 325}; 326kunit_test_suite(test_suite); 327 328MODULE_DESCRIPTION("Kunit tests for slub allocator"); 329MODULE_LICENSE("GPL");