Skip to content

Commit 1e2cd30

Browse files
committed
lib/test_stackinit: Allow building stand-alone
Especially now that GCC is developing the -ftrivial-auto-var-init option[1], it's helpful to have a stand-alone userspace test for stack variable initialization. Relicense to GPLv2+ (I am the only author), provide stand-alone kernel macro stubs, and update comments for clarity. [1] https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575198.html Signed-off-by: Kees Cook <keescook@chromium.org> Link: https://lore.kernel.org/r/20210723221933.3431999-3-keescook@chromium.org
1 parent f9398f1 commit 1e2cd30

1 file changed

Lines changed: 69 additions & 3 deletions

File tree

lib/test_stackinit.c

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,77 @@
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
1577
static u8 check_buf[MAX_VAR_SIZE];
@@ -279,6 +341,10 @@ DEFINE_TEST(user, struct test_user, STRUCT, none);
279341
static int noinline __leaf_switch_none(int path, bool fill)
280342
{
281343
switch (path) {
344+
/*
345+
* This is intentionally unreachable. To silence the
346+
* warning, build with -Wno-switch-unreachable
347+
*/
282348
uint64_t var;
283349

284350
case 1:

0 commit comments

Comments
 (0)