Merge tag 'denywrite-for-5.15' of git://github.com/davidhildenbrand/linux
[linux-2.6-microblaze.git] / lib / test_stackinit.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Test cases for compiler-based stack variable zeroing via
4  * -ftrivial-auto-var-init={zero,pattern} or CONFIG_GCC_PLUGIN_STRUCTLEAK*.
5  *
6  * External build example:
7  *      clang -O2 -Wall -ftrivial-auto-var-init=pattern \
8  *              -o test_stackinit test_stackinit.c
9  */
10 #ifdef __KERNEL__
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/string.h>
17
18 #else
19
20 /* Userspace headers. */
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <stdbool.h>
25 #include <errno.h>
26 #include <sys/types.h>
27
28 /* Linux kernel-ism stubs for stand-alone userspace build. */
29 #define KBUILD_MODNAME          "stackinit"
30 #define pr_fmt(fmt)             KBUILD_MODNAME ": " fmt
31 #define pr_err(fmt, ...)        fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__)
32 #define pr_warn(fmt, ...)       fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__)
33 #define pr_info(fmt, ...)       fprintf(stdout, pr_fmt(fmt), ##__VA_ARGS__)
34 #define __init                  /**/
35 #define __exit                  /**/
36 #define __user                  /**/
37 #define noinline                __attribute__((__noinline__))
38 #define __aligned(x)            __attribute__((__aligned__(x)))
39 #ifdef __clang__
40 # define __compiletime_error(message) /**/
41 #else
42 # define __compiletime_error(message) __attribute__((__error__(message)))
43 #endif
44 #define __compiletime_assert(condition, msg, prefix, suffix)            \
45         do {                                                            \
46                 extern void prefix ## suffix(void) __compiletime_error(msg); \
47                 if (!(condition))                                       \
48                         prefix ## suffix();                             \
49         } while (0)
50 #define _compiletime_assert(condition, msg, prefix, suffix) \
51         __compiletime_assert(condition, msg, prefix, suffix)
52 #define compiletime_assert(condition, msg) \
53         _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
54 #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
55 #define BUILD_BUG_ON(condition) \
56         BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
57 typedef uint8_t                 u8;
58 typedef uint16_t                u16;
59 typedef uint32_t                u32;
60 typedef uint64_t                u64;
61
62 #define module_init(func)       static int (*do_init)(void) = func
63 #define module_exit(func)       static void (*do_exit)(void) = func
64 #define MODULE_LICENSE(str)     int main(void) {                \
65                                         int rc;                 \
66                                         /* License: str */      \
67                                         rc = do_init();         \
68                                         if (rc == 0)            \
69                                                 do_exit();      \
70                                         return rc;              \
71                                 }
72
73 #endif /* __KERNEL__ */
74
75 /* Exfiltration buffer. */
76 #define MAX_VAR_SIZE    128
77 static u8 check_buf[MAX_VAR_SIZE];
78
79 /* Character array to trigger stack protector in all functions. */
80 #define VAR_BUFFER       32
81
82 /* Volatile mask to convince compiler to copy memory with 0xff. */
83 static volatile u8 forced_mask = 0xff;
84
85 /* Location and size tracking to validate fill and test are colocated. */
86 static void *fill_start, *target_start;
87 static size_t fill_size, target_size;
88
89 static bool range_contains(char *haystack_start, size_t haystack_size,
90                            char *needle_start, size_t needle_size)
91 {
92         if (needle_start >= haystack_start &&
93             needle_start + needle_size <= haystack_start + haystack_size)
94                 return true;
95         return false;
96 }
97
98 /* Whether the test is expected to fail. */
99 #define WANT_SUCCESS                            0
100 #define XFAIL                                   1
101
102 #define DO_NOTHING_TYPE_SCALAR(var_type)        var_type
103 #define DO_NOTHING_TYPE_STRING(var_type)        void
104 #define DO_NOTHING_TYPE_STRUCT(var_type)        void
105
106 #define DO_NOTHING_RETURN_SCALAR(ptr)           *(ptr)
107 #define DO_NOTHING_RETURN_STRING(ptr)           /**/
108 #define DO_NOTHING_RETURN_STRUCT(ptr)           /**/
109
110 #define DO_NOTHING_CALL_SCALAR(var, name)                       \
111                 (var) = do_nothing_ ## name(&(var))
112 #define DO_NOTHING_CALL_STRING(var, name)                       \
113                 do_nothing_ ## name(var)
114 #define DO_NOTHING_CALL_STRUCT(var, name)                       \
115                 do_nothing_ ## name(&(var))
116
117 #define FETCH_ARG_SCALAR(var)           &var
118 #define FETCH_ARG_STRING(var)           var
119 #define FETCH_ARG_STRUCT(var)           &var
120
121 #define FILL_SIZE_STRING                16
122
123 #define INIT_CLONE_SCALAR               /**/
124 #define INIT_CLONE_STRING               [FILL_SIZE_STRING]
125 #define INIT_CLONE_STRUCT               /**/
126
127 #define ZERO_CLONE_SCALAR(zero)         memset(&(zero), 0x00, sizeof(zero))
128 #define ZERO_CLONE_STRING(zero)         memset(&(zero), 0x00, sizeof(zero))
129 /*
130  * For the struct, intentionally poison padding to see if it gets
131  * copied out in direct assignments.
132  * */
133 #define ZERO_CLONE_STRUCT(zero)                         \
134         do {                                            \
135                 memset(&(zero), 0xFF, sizeof(zero));    \
136                 zero.one = 0;                           \
137                 zero.two = 0;                           \
138                 zero.three = 0;                         \
139                 zero.four = 0;                          \
140         } while (0)
141
142 #define INIT_SCALAR_none(var_type)      /**/
143 #define INIT_SCALAR_zero(var_type)      = 0
144
145 #define INIT_STRING_none(var_type)      [FILL_SIZE_STRING] /**/
146 #define INIT_STRING_zero(var_type)      [FILL_SIZE_STRING] = { }
147
148 #define INIT_STRUCT_none(var_type)      /**/
149 #define INIT_STRUCT_zero(var_type)      = { }
150
151
152 #define __static_partial                { .two = 0, }
153 #define __static_all                    { .one = 0,                     \
154                                           .two = 0,                     \
155                                           .three = 0,                   \
156                                           .four = 0,                    \
157                                         }
158 #define __dynamic_partial               { .two = arg->two, }
159 #define __dynamic_all                   { .one = arg->one,              \
160                                           .two = arg->two,              \
161                                           .three = arg->three,          \
162                                           .four = arg->four,            \
163                                         }
164 #define __runtime_partial               var.two = 0
165 #define __runtime_all                   var.one = 0;                    \
166                                         var.two = 0;                    \
167                                         var.three = 0;                  \
168                                         var.four = 0
169
170 #define INIT_STRUCT_static_partial(var_type)                            \
171                                         = __static_partial
172 #define INIT_STRUCT_static_all(var_type)                                \
173                                         = __static_all
174 #define INIT_STRUCT_dynamic_partial(var_type)                           \
175                                         = __dynamic_partial
176 #define INIT_STRUCT_dynamic_all(var_type)                               \
177                                         = __dynamic_all
178 #define INIT_STRUCT_runtime_partial(var_type)                           \
179                                         ; __runtime_partial
180 #define INIT_STRUCT_runtime_all(var_type)                               \
181                                         ; __runtime_all
182
183 #define INIT_STRUCT_assigned_static_partial(var_type)                   \
184                                         ; var = (var_type)__static_partial
185 #define INIT_STRUCT_assigned_static_all(var_type)                       \
186                                         ; var = (var_type)__static_all
187 #define INIT_STRUCT_assigned_dynamic_partial(var_type)                  \
188                                         ; var = (var_type)__dynamic_partial
189 #define INIT_STRUCT_assigned_dynamic_all(var_type)                      \
190                                         ; var = (var_type)__dynamic_all
191
192 #define INIT_STRUCT_assigned_copy(var_type)                             \
193                                         ; var = *(arg)
194
195 /*
196  * @name: unique string name for the test
197  * @var_type: type to be tested for zeroing initialization
198  * @which: is this a SCALAR, STRING, or STRUCT type?
199  * @init_level: what kind of initialization is performed
200  * @xfail: is this test expected to fail?
201  */
202 #define DEFINE_TEST_DRIVER(name, var_type, which, xfail)        \
203 /* Returns 0 on success, 1 on failure. */                       \
204 static noinline __init int test_ ## name (void)                 \
205 {                                                               \
206         var_type zero INIT_CLONE_ ## which;                     \
207         int ignored;                                            \
208         u8 sum = 0, i;                                          \
209                                                                 \
210         /* Notice when a new test is larger than expected. */   \
211         BUILD_BUG_ON(sizeof(zero) > MAX_VAR_SIZE);              \
212                                                                 \
213         /* Fill clone type with zero for per-field init. */     \
214         ZERO_CLONE_ ## which(zero);                             \
215         /* Clear entire check buffer for 0xFF overlap test. */  \
216         memset(check_buf, 0x00, sizeof(check_buf));             \
217         /* Fill stack with 0xFF. */                             \
218         ignored = leaf_ ##name((unsigned long)&ignored, 1,      \
219                                 FETCH_ARG_ ## which(zero));     \
220         /* Verify all bytes overwritten with 0xFF. */           \
221         for (sum = 0, i = 0; i < target_size; i++)              \
222                 sum += (check_buf[i] != 0xFF);                  \
223         if (sum) {                                              \
224                 pr_err(#name ": leaf fill was not 0xFF!?\n");   \
225                 return 1;                                       \
226         }                                                       \
227         /* Clear entire check buffer for later bit tests. */    \
228         memset(check_buf, 0x00, sizeof(check_buf));             \
229         /* Extract stack-defined variable contents. */          \
230         ignored = leaf_ ##name((unsigned long)&ignored, 0,      \
231                                 FETCH_ARG_ ## which(zero));     \
232                                                                 \
233         /* Validate that compiler lined up fill and target. */  \
234         if (!range_contains(fill_start, fill_size,              \
235                             target_start, target_size)) {       \
236                 pr_err(#name ": stack fill missed target!?\n"); \
237                 pr_err(#name ": fill %zu wide\n", fill_size);   \
238                 pr_err(#name ": target offset by %d\n", \
239                         (int)((ssize_t)(uintptr_t)fill_start -  \
240                         (ssize_t)(uintptr_t)target_start));     \
241                 return 1;                                       \
242         }                                                       \
243                                                                 \
244         /* Look for any bytes still 0xFF in check region. */    \
245         for (sum = 0, i = 0; i < target_size; i++)              \
246                 sum += (check_buf[i] == 0xFF);                  \
247                                                                 \
248         if (sum == 0) {                                         \
249                 pr_info(#name " ok\n");                         \
250                 return 0;                                       \
251         } else {                                                \
252                 pr_warn(#name " %sFAIL (uninit bytes: %d)\n",   \
253                         (xfail) ? "X" : "", sum);               \
254                 return (xfail) ? 0 : 1;                         \
255         }                                                       \
256 }
257 #define DEFINE_TEST(name, var_type, which, init_level, xfail)   \
258 /* no-op to force compiler into ignoring "uninitialized" vars */\
259 static noinline __init DO_NOTHING_TYPE_ ## which(var_type)      \
260 do_nothing_ ## name(var_type *ptr)                              \
261 {                                                               \
262         /* Will always be true, but compiler doesn't know. */   \
263         if ((unsigned long)ptr > 0x2)                           \
264                 return DO_NOTHING_RETURN_ ## which(ptr);        \
265         else                                                    \
266                 return DO_NOTHING_RETURN_ ## which(ptr + 1);    \
267 }                                                               \
268 static noinline __init int leaf_ ## name(unsigned long sp,      \
269                                          bool fill,             \
270                                          var_type *arg)         \
271 {                                                               \
272         char buf[VAR_BUFFER];                                   \
273         var_type var                                            \
274                 INIT_ ## which ## _ ## init_level(var_type);    \
275                                                                 \
276         target_start = &var;                                    \
277         target_size = sizeof(var);                              \
278         /*                                                      \
279          * Keep this buffer around to make sure we've got a     \
280          * stack frame of SOME kind...                          \
281          */                                                     \
282         memset(buf, (char)(sp & 0xff), sizeof(buf));            \
283         /* Fill variable with 0xFF. */                          \
284         if (fill) {                                             \
285                 fill_start = &var;                              \
286                 fill_size = sizeof(var);                        \
287                 memset(fill_start,                              \
288                        (char)((sp & 0xff) | forced_mask),       \
289                        fill_size);                              \
290         }                                                       \
291                                                                 \
292         /* Silence "never initialized" warnings. */             \
293         DO_NOTHING_CALL_ ## which(var, name);                   \
294                                                                 \
295         /* Exfiltrate "var". */                                 \
296         memcpy(check_buf, target_start, target_size);           \
297                                                                 \
298         return (int)buf[0] | (int)buf[sizeof(buf) - 1];         \
299 }                                                               \
300 DEFINE_TEST_DRIVER(name, var_type, which, xfail)
301
302 /* Structure with no padding. */
303 struct test_packed {
304         unsigned long one;
305         unsigned long two;
306         unsigned long three;
307         unsigned long four;
308 };
309
310 /* Simple structure with padding likely to be covered by compiler. */
311 struct test_small_hole {
312         size_t one;
313         char two;
314         /* 3 byte padding hole here. */
315         int three;
316         unsigned long four;
317 };
318
319 /* Trigger unhandled padding in a structure. */
320 struct test_big_hole {
321         u8 one;
322         u8 two;
323         u8 three;
324         /* 61 byte padding hole here. */
325         u8 four __aligned(64);
326 } __aligned(64);
327
328 struct test_trailing_hole {
329         char *one;
330         char *two;
331         char *three;
332         char four;
333         /* "sizeof(unsigned long) - 1" byte padding hole here. */
334 };
335
336 /* Test if STRUCTLEAK is clearing structs with __user fields. */
337 struct test_user {
338         u8 one;
339         unsigned long two;
340         char __user *three;
341         unsigned long four;
342 };
343
344 #define DEFINE_SCALAR_TEST(name, init, xfail)                   \
345                 DEFINE_TEST(name ## _ ## init, name, SCALAR,    \
346                             init, xfail)
347
348 #define DEFINE_SCALAR_TESTS(init, xfail)                        \
349                 DEFINE_SCALAR_TEST(u8, init, xfail);            \
350                 DEFINE_SCALAR_TEST(u16, init, xfail);           \
351                 DEFINE_SCALAR_TEST(u32, init, xfail);           \
352                 DEFINE_SCALAR_TEST(u64, init, xfail);           \
353                 DEFINE_TEST(char_array_ ## init, unsigned char, \
354                             STRING, init, xfail)
355
356 #define DEFINE_STRUCT_TEST(name, init, xfail)                   \
357                 DEFINE_TEST(name ## _ ## init,                  \
358                             struct test_ ## name, STRUCT, init, \
359                             xfail)
360
361 #define DEFINE_STRUCT_TESTS(init, xfail)                        \
362                 DEFINE_STRUCT_TEST(small_hole, init, xfail);    \
363                 DEFINE_STRUCT_TEST(big_hole, init, xfail);      \
364                 DEFINE_STRUCT_TEST(trailing_hole, init, xfail); \
365                 DEFINE_STRUCT_TEST(packed, init, xfail)
366
367 #define DEFINE_STRUCT_INITIALIZER_TESTS(base)                   \
368                 DEFINE_STRUCT_TESTS(base ## _ ## partial,       \
369                                     WANT_SUCCESS);              \
370                 DEFINE_STRUCT_TESTS(base ## _ ## all,           \
371                                     WANT_SUCCESS)
372
373 /* These should be fully initialized all the time! */
374 DEFINE_SCALAR_TESTS(zero, WANT_SUCCESS);
375 DEFINE_STRUCT_TESTS(zero, WANT_SUCCESS);
376 /* Struct initializers: padding may be left uninitialized. */
377 DEFINE_STRUCT_INITIALIZER_TESTS(static);
378 DEFINE_STRUCT_INITIALIZER_TESTS(dynamic);
379 DEFINE_STRUCT_INITIALIZER_TESTS(runtime);
380 DEFINE_STRUCT_INITIALIZER_TESTS(assigned_static);
381 DEFINE_STRUCT_INITIALIZER_TESTS(assigned_dynamic);
382 DEFINE_STRUCT_TESTS(assigned_copy, XFAIL);
383 /* No initialization without compiler instrumentation. */
384 DEFINE_SCALAR_TESTS(none, WANT_SUCCESS);
385 DEFINE_STRUCT_TESTS(none, WANT_SUCCESS);
386 /* Initialization of members with __user attribute. */
387 DEFINE_TEST(user, struct test_user, STRUCT, none, WANT_SUCCESS);
388
389 /*
390  * Check two uses through a variable declaration outside either path,
391  * which was noticed as a special case in porting earlier stack init
392  * compiler logic.
393  */
394 static int noinline __leaf_switch_none(int path, bool fill)
395 {
396         switch (path) {
397                 /*
398                  * This is intentionally unreachable. To silence the
399                  * warning, build with -Wno-switch-unreachable
400                  */
401                 uint64_t var;
402
403         case 1:
404                 target_start = &var;
405                 target_size = sizeof(var);
406                 if (fill) {
407                         fill_start = &var;
408                         fill_size = sizeof(var);
409
410                         memset(fill_start, forced_mask | 0x55, fill_size);
411                 }
412                 memcpy(check_buf, target_start, target_size);
413                 break;
414         case 2:
415                 target_start = &var;
416                 target_size = sizeof(var);
417                 if (fill) {
418                         fill_start = &var;
419                         fill_size = sizeof(var);
420
421                         memset(fill_start, forced_mask | 0xaa, fill_size);
422                 }
423                 memcpy(check_buf, target_start, target_size);
424                 break;
425         default:
426                 var = 5;
427                 return var & forced_mask;
428         }
429         return 0;
430 }
431
432 static noinline __init int leaf_switch_1_none(unsigned long sp, bool fill,
433                                               uint64_t *arg)
434 {
435         return __leaf_switch_none(1, fill);
436 }
437
438 static noinline __init int leaf_switch_2_none(unsigned long sp, bool fill,
439                                               uint64_t *arg)
440 {
441         return __leaf_switch_none(2, fill);
442 }
443
444 /*
445  * These are expected to fail for most configurations because neither
446  * GCC nor Clang have a way to perform initialization of variables in
447  * non-code areas (i.e. in a switch statement before the first "case").
448  * https://bugs.llvm.org/show_bug.cgi?id=44916
449  */
450 DEFINE_TEST_DRIVER(switch_1_none, uint64_t, SCALAR, XFAIL);
451 DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, XFAIL);
452
453 static int __init test_stackinit_init(void)
454 {
455         unsigned int failures = 0;
456
457 #define test_scalars(init)      do {                            \
458                 failures += test_u8_ ## init ();                \
459                 failures += test_u16_ ## init ();               \
460                 failures += test_u32_ ## init ();               \
461                 failures += test_u64_ ## init ();               \
462                 failures += test_char_array_ ## init ();        \
463         } while (0)
464
465 #define test_structs(init)      do {                            \
466                 failures += test_small_hole_ ## init ();        \
467                 failures += test_big_hole_ ## init ();          \
468                 failures += test_trailing_hole_ ## init ();     \
469                 failures += test_packed_ ## init ();            \
470         } while (0)
471
472         /* These are explicitly initialized and should always pass. */
473         test_scalars(zero);
474         test_structs(zero);
475         /* Padding here appears to be accidentally always initialized? */
476         test_structs(dynamic_partial);
477         test_structs(assigned_dynamic_partial);
478         /* Padding initialization depends on compiler behaviors. */
479         test_structs(static_partial);
480         test_structs(static_all);
481         test_structs(dynamic_all);
482         test_structs(runtime_partial);
483         test_structs(runtime_all);
484         test_structs(assigned_static_partial);
485         test_structs(assigned_static_all);
486         test_structs(assigned_dynamic_all);
487         /* Everything fails this since it effectively performs a memcpy(). */
488         test_structs(assigned_copy);
489
490         /* STRUCTLEAK_BYREF_ALL should cover everything from here down. */
491         test_scalars(none);
492         failures += test_switch_1_none();
493         failures += test_switch_2_none();
494
495         /* STRUCTLEAK_BYREF should cover from here down. */
496         test_structs(none);
497
498         /* STRUCTLEAK will only cover this. */
499         failures += test_user();
500
501         if (failures == 0)
502                 pr_info("all tests passed!\n");
503         else
504                 pr_err("failures: %u\n", failures);
505
506         return failures ? -EINVAL : 0;
507 }
508 module_init(test_stackinit_init);
509
510 static void __exit test_stackinit_exit(void)
511 { }
512 module_exit(test_stackinit_exit);
513
514 MODULE_LICENSE("GPL");