Commit | Line | Data |
---|---|---|
1e2cd308 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
50ceaa95 | 2 | /* |
1e2cd308 KC |
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 | |
50ceaa95 | 9 | */ |
1e2cd308 | 10 | #ifdef __KERNEL__ |
50ceaa95 KC |
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 | ||
1e2cd308 KC |
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 | ||
50ceaa95 KC |
75 | /* Exfiltration buffer. */ |
76 | #define MAX_VAR_SIZE 128 | |
8c30d32b | 77 | static u8 check_buf[MAX_VAR_SIZE]; |
50ceaa95 KC |
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 | ||
a8fc576d KC |
98 | /* Whether the test is expected to fail. */ |
99 | #define WANT_SUCCESS 0 | |
100 | #define XFAIL 1 | |
101 | ||
50ceaa95 KC |
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 | ||
a8fc576d KC |
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 | |
50ceaa95 | 144 | |
a8fc576d KC |
145 | #define INIT_STRING_none(var_type) [FILL_SIZE_STRING] /**/ |
146 | #define INIT_STRING_zero(var_type) [FILL_SIZE_STRING] = { } | |
50ceaa95 | 147 | |
a8fc576d KC |
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, \ | |
50ceaa95 | 157 | } |
a8fc576d KC |
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, \ | |
50ceaa95 | 163 | } |
a8fc576d KC |
164 | #define __runtime_partial var.two = 0 |
165 | #define __runtime_all var.one = 0; \ | |
50ceaa95 KC |
166 | var.two = 0; \ |
167 | var.three = 0; \ | |
f9398f15 | 168 | var.four = 0 |
50ceaa95 | 169 | |
a8fc576d KC |
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 | ||
50ceaa95 KC |
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 | |
9cf016e6 | 200 | * @xfail: is this test expected to fail? |
50ceaa95 | 201 | */ |
9cf016e6 | 202 | #define DEFINE_TEST_DRIVER(name, var_type, which, xfail) \ |
50ceaa95 KC |
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. */ \ | |
a8fc576d | 214 | ZERO_CLONE_ ## which(zero); \ |
8c30d32b KC |
215 | /* Clear entire check buffer for 0xFF overlap test. */ \ |
216 | memset(check_buf, 0x00, sizeof(check_buf)); \ | |
50ceaa95 KC |
217 | /* Fill stack with 0xFF. */ \ |
218 | ignored = leaf_ ##name((unsigned long)&ignored, 1, \ | |
219 | FETCH_ARG_ ## which(zero)); \ | |
8c30d32b KC |
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 | } \ | |
50ceaa95 KC |
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 | \ | |
8c30d32b KC |
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); \ | |
50ceaa95 | 247 | \ |
9cf016e6 | 248 | if (sum == 0) { \ |
50ceaa95 | 249 | pr_info(#name " ok\n"); \ |
9cf016e6 KC |
250 | return 0; \ |
251 | } else { \ | |
252 | pr_warn(#name " %sFAIL (uninit bytes: %d)\n", \ | |
253 | (xfail) ? "X" : "", sum); \ | |
254 | return (xfail) ? 0 : 1; \ | |
255 | } \ | |
50ceaa95 | 256 | } |
a8fc576d | 257 | #define DEFINE_TEST(name, var_type, which, init_level, xfail) \ |
50ceaa95 KC |
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]; \ | |
a8fc576d KC |
273 | var_type var \ |
274 | INIT_ ## which ## _ ## init_level(var_type); \ | |
50ceaa95 KC |
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 | */ \ | |
8c30d32b | 282 | memset(buf, (char)(sp & 0xff), sizeof(buf)); \ |
50ceaa95 KC |
283 | /* Fill variable with 0xFF. */ \ |
284 | if (fill) { \ | |
285 | fill_start = &var; \ | |
286 | fill_size = sizeof(var); \ | |
287 | memset(fill_start, \ | |
8c30d32b | 288 | (char)((sp & 0xff) | forced_mask), \ |
50ceaa95 KC |
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 | } \ | |
a8fc576d | 300 | DEFINE_TEST_DRIVER(name, var_type, which, xfail) |
50ceaa95 KC |
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 | ||
f9398f15 | 319 | /* Trigger unhandled padding in a structure. */ |
50ceaa95 KC |
320 | struct test_big_hole { |
321 | u8 one; | |
322 | u8 two; | |
323 | u8 three; | |
324 | /* 61 byte padding hole here. */ | |
f9398f15 | 325 | u8 four __aligned(64); |
50ceaa95 KC |
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 | ||
a8fc576d KC |
344 | #define DEFINE_SCALAR_TEST(name, init, xfail) \ |
345 | DEFINE_TEST(name ## _ ## init, name, SCALAR, \ | |
346 | init, xfail) | |
50ceaa95 | 347 | |
a8fc576d KC |
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) | |
50ceaa95 | 355 | |
a8fc576d | 356 | #define DEFINE_STRUCT_TEST(name, init, xfail) \ |
50ceaa95 | 357 | DEFINE_TEST(name ## _ ## init, \ |
a8fc576d KC |
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) | |
50ceaa95 | 366 | |
a8fc576d KC |
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) | |
50ceaa95 KC |
372 | |
373 | /* These should be fully initialized all the time! */ | |
a8fc576d KC |
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); | |
50ceaa95 | 383 | /* No initialization without compiler instrumentation. */ |
a8fc576d KC |
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); | |
50ceaa95 KC |
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) { | |
1e2cd308 KC |
397 | /* |
398 | * This is intentionally unreachable. To silence the | |
399 | * warning, build with -Wno-switch-unreachable | |
400 | */ | |
50ceaa95 KC |
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 | ||
9cf016e6 KC |
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 | */ | |
a8fc576d KC |
450 | DEFINE_TEST_DRIVER(switch_1_none, uint64_t, SCALAR, XFAIL); |
451 | DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, XFAIL); | |
50ceaa95 KC |
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); | |
a8fc576d | 477 | test_structs(assigned_dynamic_partial); |
50ceaa95 KC |
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); | |
a8fc576d KC |
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); | |
50ceaa95 KC |
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"); |