1 // SPDX-License-Identifier: GPL-2.0
2 #include <kunit/test.h>
3 #include <kunit/test-bug.h>
5 #include <linux/slab.h>
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/rcupdate.h>
9 #include "../mm/slab.h"
11 static struct kunit_resource resource
;
12 static int slab_errors
;
15 * Wrapper function for kmem_cache_create(), which reduces 2 parameters:
16 * 'align' and 'ctor', and sets SLAB_SKIP_KFENCE flag to avoid getting an
17 * object from kfence pool, where the operation could be caught by both
18 * our test and kfence sanity check.
20 static struct kmem_cache
*test_kmem_cache_create(const char *name
,
21 unsigned int size
, slab_flags_t flags
)
23 struct kmem_cache
*s
= kmem_cache_create(name
, size
, 0,
24 (flags
| SLAB_NO_USER_FLAGS
), NULL
);
25 s
->flags
|= SLAB_SKIP_KFENCE
;
29 static void test_clobber_zone(struct kunit
*test
)
31 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_RZ_alloc", 64,
33 u8
*p
= kmem_cache_alloc(s
, GFP_KERNEL
);
35 kasan_disable_current();
38 validate_slab_cache(s
);
39 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
41 kasan_enable_current();
42 kmem_cache_free(s
, p
);
43 kmem_cache_destroy(s
);
47 static void test_next_pointer(struct kunit
*test
)
49 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_next_ptr_free",
51 u8
*p
= kmem_cache_alloc(s
, GFP_KERNEL
);
53 unsigned long *ptr_addr
;
55 kmem_cache_free(s
, p
);
57 ptr_addr
= (unsigned long *)(p
+ s
->offset
);
59 p
[s
->offset
] = ~p
[s
->offset
];
62 * Expecting three errors.
63 * One for the corrupted freechain and the other one for the wrong
64 * count of objects in use. The third error is fixing broken cache.
66 validate_slab_cache(s
);
67 KUNIT_EXPECT_EQ(test
, 3, slab_errors
);
70 * Try to repair corrupted freepointer.
71 * Still expecting two errors. The first for the wrong count
73 * The second error is for fixing broken cache.
78 validate_slab_cache(s
);
79 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
82 * Previous validation repaired the count of objects in use.
83 * Now expecting no error.
86 validate_slab_cache(s
);
87 KUNIT_EXPECT_EQ(test
, 0, slab_errors
);
89 kmem_cache_destroy(s
);
92 static void test_first_word(struct kunit
*test
)
94 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_1th_word_free",
96 u8
*p
= kmem_cache_alloc(s
, GFP_KERNEL
);
98 kmem_cache_free(s
, p
);
101 validate_slab_cache(s
);
102 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
104 kmem_cache_destroy(s
);
107 static void test_clobber_50th_byte(struct kunit
*test
)
109 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_50th_word_free",
111 u8
*p
= kmem_cache_alloc(s
, GFP_KERNEL
);
113 kmem_cache_free(s
, p
);
116 validate_slab_cache(s
);
117 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
119 kmem_cache_destroy(s
);
123 static void test_clobber_redzone_free(struct kunit
*test
)
125 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_RZ_free", 64,
127 u8
*p
= kmem_cache_alloc(s
, GFP_KERNEL
);
129 kasan_disable_current();
130 kmem_cache_free(s
, p
);
133 validate_slab_cache(s
);
134 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
136 kasan_enable_current();
137 kmem_cache_destroy(s
);
140 static void test_kmalloc_redzone_access(struct kunit
*test
)
142 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_RZ_kmalloc", 32,
143 SLAB_KMALLOC
|SLAB_STORE_USER
|SLAB_RED_ZONE
);
144 u8
*p
= alloc_hooks(__kmalloc_cache_noprof(s
, GFP_KERNEL
, 18));
146 kasan_disable_current();
148 /* Suppress the -Warray-bounds warning */
149 OPTIMIZER_HIDE_VAR(p
);
153 validate_slab_cache(s
);
154 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
156 kasan_enable_current();
157 kmem_cache_free(s
, p
);
158 kmem_cache_destroy(s
);
161 struct test_kfree_rcu_struct
{
165 static void test_kfree_rcu(struct kunit
*test
)
167 struct kmem_cache
*s
;
168 struct test_kfree_rcu_struct
*p
;
170 if (IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST
))
171 kunit_skip(test
, "can't do kfree_rcu() when test is built-in");
173 s
= test_kmem_cache_create("TestSlub_kfree_rcu",
174 sizeof(struct test_kfree_rcu_struct
),
176 p
= kmem_cache_alloc(s
, GFP_KERNEL
);
179 kmem_cache_destroy(s
);
181 KUNIT_EXPECT_EQ(test
, 0, slab_errors
);
184 static void test_leak_destroy(struct kunit
*test
)
186 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_leak_destroy",
188 kmem_cache_alloc(s
, GFP_KERNEL
);
190 kmem_cache_destroy(s
);
192 KUNIT_EXPECT_EQ(test
, 2, slab_errors
);
195 static void test_krealloc_redzone_zeroing(struct kunit
*test
)
199 struct kmem_cache
*s
= test_kmem_cache_create("TestSlub_krealloc", 64,
200 SLAB_KMALLOC
|SLAB_STORE_USER
|SLAB_RED_ZONE
);
202 p
= alloc_hooks(__kmalloc_cache_noprof(s
, GFP_KERNEL
, 48));
205 kasan_disable_current();
206 OPTIMIZER_HIDE_VAR(p
);
209 p
= krealloc(p
, 40, GFP_KERNEL
| __GFP_ZERO
);
210 for (i
= 40; i
< 64; i
++)
211 KUNIT_EXPECT_EQ(test
, p
[i
], SLUB_RED_ACTIVE
);
213 /* Test grow within the same 64B kmalloc object */
214 p
= krealloc(p
, 56, GFP_KERNEL
| __GFP_ZERO
);
215 for (i
= 40; i
< 56; i
++)
216 KUNIT_EXPECT_EQ(test
, p
[i
], 0);
217 for (i
= 56; i
< 64; i
++)
218 KUNIT_EXPECT_EQ(test
, p
[i
], SLUB_RED_ACTIVE
);
220 validate_slab_cache(s
);
221 KUNIT_EXPECT_EQ(test
, 0, slab_errors
);
224 /* Test grow with allocating a bigger 128B object */
225 p
= krealloc(p
, 112, GFP_KERNEL
| __GFP_ZERO
);
226 for (i
= 0; i
< 56; i
++)
227 KUNIT_EXPECT_EQ(test
, p
[i
], 0xff);
228 for (i
= 56; i
< 112; i
++)
229 KUNIT_EXPECT_EQ(test
, p
[i
], 0);
232 kasan_enable_current();
233 kmem_cache_destroy(s
);
236 static int test_init(struct kunit
*test
)
240 kunit_add_named_resource(test
, NULL
, NULL
, &resource
,
241 "slab_errors", &slab_errors
);
245 static struct kunit_case test_cases
[] = {
246 KUNIT_CASE(test_clobber_zone
),
249 KUNIT_CASE(test_next_pointer
),
250 KUNIT_CASE(test_first_word
),
251 KUNIT_CASE(test_clobber_50th_byte
),
254 KUNIT_CASE(test_clobber_redzone_free
),
255 KUNIT_CASE(test_kmalloc_redzone_access
),
256 KUNIT_CASE(test_kfree_rcu
),
257 KUNIT_CASE(test_leak_destroy
),
258 KUNIT_CASE(test_krealloc_redzone_zeroing
),
262 static struct kunit_suite test_suite
= {
265 .test_cases
= test_cases
,
267 kunit_test_suite(test_suite
);
269 MODULE_LICENSE("GPL");