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