Merge tag 'io_uring-6.5-2023-07-03' of git://git.kernel.dk/linux
[platform/kernel/linux-starfive.git] / lib / fortify_kunit.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Runtime test cases for CONFIG_FORTIFY_SOURCE that aren't expected to
4  * Oops the kernel on success. (For those, see drivers/misc/lkdtm/fortify.c)
5  *
6  * For corner cases with UBSAN, try testing with:
7  *
8  * ./tools/testing/kunit/kunit.py run --arch=x86_64 \
9  *      --kconfig_add CONFIG_FORTIFY_SOURCE=y \
10  *      --kconfig_add CONFIG_UBSAN=y \
11  *      --kconfig_add CONFIG_UBSAN_TRAP=y \
12  *      --kconfig_add CONFIG_UBSAN_BOUNDS=y \
13  *      --kconfig_add CONFIG_UBSAN_LOCAL_BOUNDS=y \
14  *      --make_options LLVM=1 fortify
15  */
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18 #include <kunit/test.h>
19 #include <linux/device.h>
20 #include <linux/slab.h>
21 #include <linux/string.h>
22 #include <linux/vmalloc.h>
23
24 static const char array_of_10[] = "this is 10";
25 static const char *ptr_of_11 = "this is 11!";
26 static char array_unknown[] = "compiler thinks I might change";
27
28 /* Handle being built without CONFIG_FORTIFY_SOURCE */
29 #ifndef __compiletime_strlen
30 # define __compiletime_strlen __builtin_strlen
31 #endif
32
33 static void known_sizes_test(struct kunit *test)
34 {
35         KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8);
36         KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10);
37         KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11);
38
39         KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_unknown), SIZE_MAX);
40         /* Externally defined and dynamically sized string pointer: */
41         KUNIT_EXPECT_EQ(test, __compiletime_strlen(test->name), SIZE_MAX);
42 }
43
44 /* This is volatile so the optimizer can't perform DCE below. */
45 static volatile int pick;
46
47 /* Not inline to keep optimizer from figuring out which string we want. */
48 static noinline size_t want_minus_one(int pick)
49 {
50         const char *str;
51
52         switch (pick) {
53         case 1:
54                 str = "4444";
55                 break;
56         case 2:
57                 str = "333";
58                 break;
59         default:
60                 str = "1";
61                 break;
62         }
63         return __compiletime_strlen(str);
64 }
65
66 static void control_flow_split_test(struct kunit *test)
67 {
68         KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX);
69 }
70
71 #define KUNIT_EXPECT_BOS(test, p, expected, name)                       \
72         KUNIT_EXPECT_EQ_MSG(test, __builtin_object_size(p, 1),          \
73                 expected,                                               \
74                 "__alloc_size() not working with __bos on " name "\n")
75
76 #if !__has_builtin(__builtin_dynamic_object_size)
77 #define KUNIT_EXPECT_BDOS(test, p, expected, name)                      \
78         /* Silence "unused variable 'expected'" warning. */             \
79         KUNIT_EXPECT_EQ(test, expected, expected)
80 #else
81 #define KUNIT_EXPECT_BDOS(test, p, expected, name)                      \
82         KUNIT_EXPECT_EQ_MSG(test, __builtin_dynamic_object_size(p, 1),  \
83                 expected,                                               \
84                 "__alloc_size() not working with __bdos on " name "\n")
85 #endif
86
87 /* If the execpted size is a constant value, __bos can see it. */
88 #define check_const(_expected, alloc, free)             do {            \
89         size_t expected = (_expected);                                  \
90         void *p = alloc;                                                \
91         KUNIT_EXPECT_TRUE_MSG(test, p != NULL, #alloc " failed?!\n");   \
92         KUNIT_EXPECT_BOS(test, p, expected, #alloc);                    \
93         KUNIT_EXPECT_BDOS(test, p, expected, #alloc);                   \
94         free;                                                           \
95 } while (0)
96
97 /* If the execpted size is NOT a constant value, __bos CANNOT see it. */
98 #define check_dynamic(_expected, alloc, free)           do {            \
99         size_t expected = (_expected);                                  \
100         void *p = alloc;                                                \
101         KUNIT_EXPECT_TRUE_MSG(test, p != NULL, #alloc " failed?!\n");   \
102         KUNIT_EXPECT_BOS(test, p, SIZE_MAX, #alloc);                    \
103         KUNIT_EXPECT_BDOS(test, p, expected, #alloc);                   \
104         free;                                                           \
105 } while (0)
106
107 /* Assortment of constant-value kinda-edge cases. */
108 #define CONST_TEST_BODY(TEST_alloc)     do {                            \
109         /* Special-case vmalloc()-family to skip 0-sized allocs. */     \
110         if (strcmp(#TEST_alloc, "TEST_vmalloc") != 0)                   \
111                 TEST_alloc(check_const, 0, 0);                          \
112         TEST_alloc(check_const, 1, 1);                                  \
113         TEST_alloc(check_const, 128, 128);                              \
114         TEST_alloc(check_const, 1023, 1023);                            \
115         TEST_alloc(check_const, 1025, 1025);                            \
116         TEST_alloc(check_const, 4096, 4096);                            \
117         TEST_alloc(check_const, 4097, 4097);                            \
118 } while (0)
119
120 static volatile size_t zero_size;
121 static volatile size_t unknown_size = 50;
122
123 #if !__has_builtin(__builtin_dynamic_object_size)
124 #define DYNAMIC_TEST_BODY(TEST_alloc)                                   \
125         kunit_skip(test, "Compiler is missing __builtin_dynamic_object_size() support\n")
126 #else
127 #define DYNAMIC_TEST_BODY(TEST_alloc)   do {                            \
128         size_t size = unknown_size;                                     \
129                                                                         \
130         /*                                                              \
131          * Expected size is "size" in each test, before it is then      \
132          * internally incremented in each test. Requires we disable     \
133          * -Wunsequenced.                                               \
134          */                                                             \
135         TEST_alloc(check_dynamic, size, size++);                        \
136         /* Make sure incrementing actually happened. */                 \
137         KUNIT_EXPECT_NE(test, size, unknown_size);                      \
138 } while (0)
139 #endif
140
141 #define DEFINE_ALLOC_SIZE_TEST_PAIR(allocator)                          \
142 static void alloc_size_##allocator##_const_test(struct kunit *test)     \
143 {                                                                       \
144         CONST_TEST_BODY(TEST_##allocator);                              \
145 }                                                                       \
146 static void alloc_size_##allocator##_dynamic_test(struct kunit *test)   \
147 {                                                                       \
148         DYNAMIC_TEST_BODY(TEST_##allocator);                            \
149 }
150
151 #define TEST_kmalloc(checker, expected_size, alloc_size)        do {    \
152         gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;                          \
153         void *orig;                                                     \
154         size_t len;                                                     \
155                                                                         \
156         checker(expected_size, kmalloc(alloc_size, gfp),                \
157                 kfree(p));                                              \
158         checker(expected_size,                                          \
159                 kmalloc_node(alloc_size, gfp, NUMA_NO_NODE),            \
160                 kfree(p));                                              \
161         checker(expected_size, kzalloc(alloc_size, gfp),                \
162                 kfree(p));                                              \
163         checker(expected_size,                                          \
164                 kzalloc_node(alloc_size, gfp, NUMA_NO_NODE),            \
165                 kfree(p));                                              \
166         checker(expected_size, kcalloc(1, alloc_size, gfp),             \
167                 kfree(p));                                              \
168         checker(expected_size, kcalloc(alloc_size, 1, gfp),             \
169                 kfree(p));                                              \
170         checker(expected_size,                                          \
171                 kcalloc_node(1, alloc_size, gfp, NUMA_NO_NODE),         \
172                 kfree(p));                                              \
173         checker(expected_size,                                          \
174                 kcalloc_node(alloc_size, 1, gfp, NUMA_NO_NODE),         \
175                 kfree(p));                                              \
176         checker(expected_size, kmalloc_array(1, alloc_size, gfp),       \
177                 kfree(p));                                              \
178         checker(expected_size, kmalloc_array(alloc_size, 1, gfp),       \
179                 kfree(p));                                              \
180         checker(expected_size,                                          \
181                 kmalloc_array_node(1, alloc_size, gfp, NUMA_NO_NODE),   \
182                 kfree(p));                                              \
183         checker(expected_size,                                          \
184                 kmalloc_array_node(alloc_size, 1, gfp, NUMA_NO_NODE),   \
185                 kfree(p));                                              \
186         checker(expected_size, __kmalloc(alloc_size, gfp),              \
187                 kfree(p));                                              \
188         checker(expected_size,                                          \
189                 __kmalloc_node(alloc_size, gfp, NUMA_NO_NODE),          \
190                 kfree(p));                                              \
191                                                                         \
192         orig = kmalloc(alloc_size, gfp);                                \
193         KUNIT_EXPECT_TRUE(test, orig != NULL);                          \
194         checker((expected_size) * 2,                                    \
195                 krealloc(orig, (alloc_size) * 2, gfp),                  \
196                 kfree(p));                                              \
197         orig = kmalloc(alloc_size, gfp);                                \
198         KUNIT_EXPECT_TRUE(test, orig != NULL);                          \
199         checker((expected_size) * 2,                                    \
200                 krealloc_array(orig, 1, (alloc_size) * 2, gfp),         \
201                 kfree(p));                                              \
202         orig = kmalloc(alloc_size, gfp);                                \
203         KUNIT_EXPECT_TRUE(test, orig != NULL);                          \
204         checker((expected_size) * 2,                                    \
205                 krealloc_array(orig, (alloc_size) * 2, 1, gfp),         \
206                 kfree(p));                                              \
207                                                                         \
208         len = 11;                                                       \
209         /* Using memdup() with fixed size, so force unknown length. */  \
210         if (!__builtin_constant_p(expected_size))                       \
211                 len += zero_size;                                       \
212         checker(len, kmemdup("hello there", len, gfp), kfree(p));       \
213 } while (0)
214 DEFINE_ALLOC_SIZE_TEST_PAIR(kmalloc)
215
216 /* Sizes are in pages, not bytes. */
217 #define TEST_vmalloc(checker, expected_pages, alloc_pages)      do {    \
218         gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;                          \
219         checker((expected_pages) * PAGE_SIZE,                           \
220                 vmalloc((alloc_pages) * PAGE_SIZE),        vfree(p));   \
221         checker((expected_pages) * PAGE_SIZE,                           \
222                 vzalloc((alloc_pages) * PAGE_SIZE),        vfree(p));   \
223         checker((expected_pages) * PAGE_SIZE,                           \
224                 __vmalloc((alloc_pages) * PAGE_SIZE, gfp), vfree(p));   \
225 } while (0)
226 DEFINE_ALLOC_SIZE_TEST_PAIR(vmalloc)
227
228 /* Sizes are in pages (and open-coded for side-effects), not bytes. */
229 #define TEST_kvmalloc(checker, expected_pages, alloc_pages)     do {    \
230         gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;                          \
231         size_t prev_size;                                               \
232         void *orig;                                                     \
233                                                                         \
234         checker((expected_pages) * PAGE_SIZE,                           \
235                 kvmalloc((alloc_pages) * PAGE_SIZE, gfp),               \
236                 vfree(p));                                              \
237         checker((expected_pages) * PAGE_SIZE,                           \
238                 kvmalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \
239                 vfree(p));                                              \
240         checker((expected_pages) * PAGE_SIZE,                           \
241                 kvzalloc((alloc_pages) * PAGE_SIZE, gfp),               \
242                 vfree(p));                                              \
243         checker((expected_pages) * PAGE_SIZE,                           \
244                 kvzalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \
245                 vfree(p));                                              \
246         checker((expected_pages) * PAGE_SIZE,                           \
247                 kvcalloc(1, (alloc_pages) * PAGE_SIZE, gfp),            \
248                 vfree(p));                                              \
249         checker((expected_pages) * PAGE_SIZE,                           \
250                 kvcalloc((alloc_pages) * PAGE_SIZE, 1, gfp),            \
251                 vfree(p));                                              \
252         checker((expected_pages) * PAGE_SIZE,                           \
253                 kvmalloc_array(1, (alloc_pages) * PAGE_SIZE, gfp),      \
254                 vfree(p));                                              \
255         checker((expected_pages) * PAGE_SIZE,                           \
256                 kvmalloc_array((alloc_pages) * PAGE_SIZE, 1, gfp),      \
257                 vfree(p));                                              \
258                                                                         \
259         prev_size = (expected_pages) * PAGE_SIZE;                       \
260         orig = kvmalloc(prev_size, gfp);                                \
261         KUNIT_EXPECT_TRUE(test, orig != NULL);                          \
262         checker(((expected_pages) * PAGE_SIZE) * 2,                     \
263                 kvrealloc(orig, prev_size,                              \
264                           ((alloc_pages) * PAGE_SIZE) * 2, gfp),        \
265                 kvfree(p));                                             \
266 } while (0)
267 DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc)
268
269 #define TEST_devm_kmalloc(checker, expected_size, alloc_size)   do {    \
270         gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;                          \
271         const char dev_name[] = "fortify-test";                         \
272         struct device *dev;                                             \
273         void *orig;                                                     \
274         size_t len;                                                     \
275                                                                         \
276         /* Create dummy device for devm_kmalloc()-family tests. */      \
277         dev = root_device_register(dev_name);                           \
278         KUNIT_ASSERT_FALSE_MSG(test, IS_ERR(dev),                       \
279                                "Cannot register test device\n");        \
280                                                                         \
281         checker(expected_size, devm_kmalloc(dev, alloc_size, gfp),      \
282                 devm_kfree(dev, p));                                    \
283         checker(expected_size, devm_kzalloc(dev, alloc_size, gfp),      \
284                 devm_kfree(dev, p));                                    \
285         checker(expected_size,                                          \
286                 devm_kmalloc_array(dev, 1, alloc_size, gfp),            \
287                 devm_kfree(dev, p));                                    \
288         checker(expected_size,                                          \
289                 devm_kmalloc_array(dev, alloc_size, 1, gfp),            \
290                 devm_kfree(dev, p));                                    \
291         checker(expected_size,                                          \
292                 devm_kcalloc(dev, 1, alloc_size, gfp),                  \
293                 devm_kfree(dev, p));                                    \
294         checker(expected_size,                                          \
295                 devm_kcalloc(dev, alloc_size, 1, gfp),                  \
296                 devm_kfree(dev, p));                                    \
297                                                                         \
298         orig = devm_kmalloc(dev, alloc_size, gfp);                      \
299         KUNIT_EXPECT_TRUE(test, orig != NULL);                          \
300         checker((expected_size) * 2,                                    \
301                 devm_krealloc(dev, orig, (alloc_size) * 2, gfp),        \
302                 devm_kfree(dev, p));                                    \
303                                                                         \
304         len = 4;                                                        \
305         /* Using memdup() with fixed size, so force unknown length. */  \
306         if (!__builtin_constant_p(expected_size))                       \
307                 len += zero_size;                                       \
308         checker(len, devm_kmemdup(dev, "Ohai", len, gfp),               \
309                 devm_kfree(dev, p));                                    \
310                                                                         \
311         device_unregister(dev);                                         \
312 } while (0)
313 DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc)
314
315 static int fortify_test_init(struct kunit *test)
316 {
317         if (!IS_ENABLED(CONFIG_FORTIFY_SOURCE))
318                 kunit_skip(test, "Not built with CONFIG_FORTIFY_SOURCE=y");
319
320         return 0;
321 }
322
323 static struct kunit_case fortify_test_cases[] = {
324         KUNIT_CASE(known_sizes_test),
325         KUNIT_CASE(control_flow_split_test),
326         KUNIT_CASE(alloc_size_kmalloc_const_test),
327         KUNIT_CASE(alloc_size_kmalloc_dynamic_test),
328         KUNIT_CASE(alloc_size_vmalloc_const_test),
329         KUNIT_CASE(alloc_size_vmalloc_dynamic_test),
330         KUNIT_CASE(alloc_size_kvmalloc_const_test),
331         KUNIT_CASE(alloc_size_kvmalloc_dynamic_test),
332         KUNIT_CASE(alloc_size_devm_kmalloc_const_test),
333         KUNIT_CASE(alloc_size_devm_kmalloc_dynamic_test),
334         {}
335 };
336
337 static struct kunit_suite fortify_test_suite = {
338         .name = "fortify",
339         .init = fortify_test_init,
340         .test_cases = fortify_test_cases,
341 };
342
343 kunit_test_suite(fortify_test_suite);
344
345 MODULE_LICENSE("GPL");