Merge tag 'core-debugobjects-2022-12-10' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / lib / slub_kunit.c
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");