1- // SPDX-License-Identifier: GPL-2.0
1+ // SPDX-License-Identifier: GPL-2.0-or-later
22/*
3- * Test cases for compiler-based stack variable zeroing via future
4- * compiler flags or CONFIG_GCC_PLUGIN_STRUCTLEAK*.
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
59 */
10+ #ifdef __KERNEL__
611#define pr_fmt (fmt ) KBUILD_MODNAME ": " fmt
712
813#include <linux/init.h>
914#include <linux/kernel.h>
1015#include <linux/module.h>
1116#include <linux/string.h>
1217
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+
1375/* Exfiltration buffer. */
1476#define MAX_VAR_SIZE 128
1577static u8 check_buf [MAX_VAR_SIZE ];
@@ -33,6 +95,10 @@ static bool range_contains(char *haystack_start, size_t haystack_size,
3395 return false;
3496}
3597
98+ /* Whether the test is expected to fail. */
99+ #define WANT_SUCCESS 0
100+ #define XFAIL 1
101+
36102#define DO_NOTHING_TYPE_SCALAR (var_type ) var_type
37103#define DO_NOTHING_TYPE_STRING (var_type ) void
38104#define DO_NOTHING_TYPE_STRUCT (var_type ) void
@@ -58,34 +124,73 @@ static bool range_contains(char *haystack_start, size_t haystack_size,
58124#define INIT_CLONE_STRING [FILL_SIZE_STRING]
59125#define INIT_CLONE_STRUCT /**/
60126
61- #define INIT_SCALAR_none /**/
62- #define INIT_SCALAR_zero = 0
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
63144
64- #define INIT_STRING_none [FILL_SIZE_STRING] /**/
65- #define INIT_STRING_zero [FILL_SIZE_STRING] = { }
145+ #define INIT_STRING_none ( var_type ) [FILL_SIZE_STRING] /**/
146+ #define INIT_STRING_zero ( var_type ) [FILL_SIZE_STRING] = { }
66147
67- #define INIT_STRUCT_none /**/
68- #define INIT_STRUCT_zero = { }
69- #define INIT_STRUCT_static_partial = { .two = 0, }
70- #define INIT_STRUCT_static_all = { .one = arg->one, \
71- .two = arg->two, \
72- .three = arg->three, \
73- .four = arg->four, \
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, \
74157 }
75- #define INIT_STRUCT_dynamic_partial = { .two = arg->two, }
76- #define INIT_STRUCT_dynamic_all = { .one = arg->one, \
77- .two = arg->two, \
78- .three = arg->three, \
79- .four = arg->four, \
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, \
80163 }
81- #define INIT_STRUCT_runtime_partial ; \
82- var.two = 0
83- #define INIT_STRUCT_runtime_all ; \
84- var.one = 0; \
164+ #define __runtime_partial var.two = 0
165+ #define __runtime_all var.one = 0; \
85166 var.two = 0; \
86167 var.three = 0; \
87- memset(&var.four, 0, \
88- sizeof(var.four))
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)
89194
90195/*
91196 * @name: unique string name for the test
@@ -106,7 +211,7 @@ static noinline __init int test_ ## name (void) \
106211 BUILD_BUG_ON (sizeof (zero ) > MAX_VAR_SIZE ); \
107212 \
108213 /* Fill clone type with zero for per-field init. */ \
109- memset ( & zero , 0x00 , sizeof (zero )); \
214+ ZERO_CLONE_ # # which (zero); \
110215 /* Clear entire check buffer for 0xFF overlap test. */ \
111216 memset (check_buf , 0x00 , sizeof (check_buf )); \
112217 /* Fill stack with 0xFF. */ \
@@ -149,7 +254,7 @@ static noinline __init int test_ ## name (void) \
149254 return (xfail) ? 0 : 1; \
150255 } \
151256}
152- #define DEFINE_TEST (name , var_type , which , init_level ) \
257+ #define DEFINE_TEST (name , var_type , which , init_level , xfail ) \
153258/* no-op to force compiler into ignoring "uninitialized" vars */ \
154259static noinline __init DO_NOTHING_TYPE_ ## which(var_type) \
155260do_nothing_ ## name(var_type *ptr) \
@@ -165,7 +270,8 @@ static noinline __init int leaf_ ## name(unsigned long sp, \
165270 var_type *arg) \
166271{ \
167272 char buf[VAR_BUFFER]; \
168- var_type var INIT_ ## which ## _ ## init_level; \
273+ var_type var \
274+ INIT_ ## which ## _ ## init_level(var_type); \
169275 \
170276 target_start = &var; \
171277 target_size = sizeof(var); \
@@ -191,7 +297,7 @@ static noinline __init int leaf_ ## name(unsigned long sp, \
191297 \
192298 return (int )buf [0 ] | (int )buf [sizeof (buf ) - 1 ]; \
193299} \
194- DEFINE_TEST_DRIVER (name , var_type , which , 0 )
300+ DEFINE_TEST_DRIVER (name , var_type , which , xfail )
195301
196302/* Structure with no padding. */
197303struct test_packed {
@@ -210,18 +316,13 @@ struct test_small_hole {
210316 unsigned long four ;
211317};
212318
213- /* Try to trigger unhandled padding in a structure. */
214- struct test_aligned {
215- u32 internal1 ;
216- u64 internal2 ;
217- } __aligned (64 );
218-
319+ /* Trigger unhandled padding in a structure. */
219320struct test_big_hole {
220321 u8 one ;
221322 u8 two ;
222323 u8 three ;
223324 /* 61 byte padding hole here. */
224- struct test_aligned four ;
325+ u8 four __aligned ( 64 ) ;
225326} __aligned (64 );
226327
227328struct test_trailing_hole {
@@ -240,42 +341,50 @@ struct test_user {
240341 unsigned long four ;
241342};
242343
243- #define DEFINE_SCALAR_TEST (name , init ) \
244- DEFINE_TEST(name ## _ ## init, name, SCALAR, init)
344+ #define DEFINE_SCALAR_TEST (name , init , xfail ) \
345+ DEFINE_TEST(name ## _ ## init, name, SCALAR, \
346+ init, xfail)
245347
246- #define DEFINE_SCALAR_TESTS (init ) \
247- DEFINE_SCALAR_TEST(u8, init); \
248- DEFINE_SCALAR_TEST(u16, init); \
249- DEFINE_SCALAR_TEST(u32, init); \
250- DEFINE_SCALAR_TEST(u64, init); \
251- DEFINE_TEST(char_array_ ## init, unsigned char, STRING, init)
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)
252355
253- #define DEFINE_STRUCT_TEST (name , init ) \
356+ #define DEFINE_STRUCT_TEST (name , init , xfail ) \
254357 DEFINE_TEST(name ## _ ## init, \
255- struct test_ ## name, STRUCT, 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)
256366
257- #define DEFINE_STRUCT_TESTS ( init ) \
258- DEFINE_STRUCT_TEST(small_hole, init); \
259- DEFINE_STRUCT_TEST(big_hole, init ); \
260- DEFINE_STRUCT_TEST(trailing_hole, init); \
261- DEFINE_STRUCT_TEST(packed, init )
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 )
262372
263373/* These should be fully initialized all the time! */
264- DEFINE_SCALAR_TESTS (zero );
265- DEFINE_STRUCT_TESTS (zero );
266- /* Static initialization: padding may be left uninitialized. */
267- DEFINE_STRUCT_TESTS (static_partial );
268- DEFINE_STRUCT_TESTS (static_all );
269- /* Dynamic initialization: padding may be left uninitialized. */
270- DEFINE_STRUCT_TESTS (dynamic_partial );
271- DEFINE_STRUCT_TESTS (dynamic_all );
272- /* Runtime initialization: padding may be left uninitialized. */
273- DEFINE_STRUCT_TESTS (runtime_partial );
274- DEFINE_STRUCT_TESTS (runtime_all );
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 );
275383/* No initialization without compiler instrumentation. */
276- DEFINE_SCALAR_TESTS (none );
277- DEFINE_STRUCT_TESTS (none );
278- DEFINE_TEST (user , struct test_user , STRUCT , none );
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 );
279388
280389/*
281390 * Check two uses through a variable declaration outside either path,
@@ -285,6 +394,10 @@ DEFINE_TEST(user, struct test_user, STRUCT, none);
285394static int noinline __leaf_switch_none (int path , bool fill )
286395{
287396 switch (path ) {
397+ /*
398+ * This is intentionally unreachable. To silence the
399+ * warning, build with -Wno-switch-unreachable
400+ */
288401 uint64_t var ;
289402
290403 case 1 :
@@ -334,8 +447,8 @@ static noinline __init int leaf_switch_2_none(unsigned long sp, bool fill,
334447 * non-code areas (i.e. in a switch statement before the first "case").
335448 * https://bugs.llvm.org/show_bug.cgi?id=44916
336449 */
337- DEFINE_TEST_DRIVER (switch_1_none , uint64_t , SCALAR , 1 );
338- DEFINE_TEST_DRIVER (switch_2_none , uint64_t , SCALAR , 1 );
450+ DEFINE_TEST_DRIVER (switch_1_none , uint64_t , SCALAR , XFAIL );
451+ DEFINE_TEST_DRIVER (switch_2_none , uint64_t , SCALAR , XFAIL );
339452
340453static int __init test_stackinit_init (void )
341454{
@@ -361,12 +474,18 @@ static int __init test_stackinit_init(void)
361474 test_structs (zero );
362475 /* Padding here appears to be accidentally always initialized? */
363476 test_structs (dynamic_partial );
477+ test_structs (assigned_dynamic_partial );
364478 /* Padding initialization depends on compiler behaviors. */
365479 test_structs (static_partial );
366480 test_structs (static_all );
367481 test_structs (dynamic_all );
368482 test_structs (runtime_partial );
369483 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 );
370489
371490 /* STRUCTLEAK_BYREF_ALL should cover everything from here down. */
372491 test_scalars (none );
0 commit comments