Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Kbuild: remove structleak gcc plugin

gcc-12 and higher support the -ftrivial-auto-var-init= flag, after
gcc-8 is the minimum version, this is half of the supported ones, and
the vast majority of the versions that users are actually likely to
have, so it seems like a good time to stop having the fallback
plugin implementation

Older toolchains are still able to build kernels normally without
this plugin, but won't be able to use variable initialization..

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+3 -370
+1 -5
drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
··· 86 86 87 87 #define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel) 88 88 89 - /* 90 - * noinline_for_stack so we don't get multiple copies of tx_buf 91 - * on the stack in case of gcc-plugin-structleak 92 - */ 93 - static int noinline_for_stack 89 + static int 94 90 jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err) 95 91 { 96 92 struct spi_device *spi = lcd->spi;
+1 -3
lib/Kconfig.debug
··· 2870 2870 help 2871 2871 Test if the kernel is zero-initializing stack variables and 2872 2872 padding. Coverage is controlled by compiler flags, 2873 - CONFIG_INIT_STACK_ALL_PATTERN, CONFIG_INIT_STACK_ALL_ZERO, 2874 - CONFIG_GCC_PLUGIN_STRUCTLEAK, CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF, 2875 - or CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL. 2873 + CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_ALL_ZERO. 2876 2874 2877 2875 config FORTIFY_KUNIT_TEST 2878 2876 tristate "Test fortified str*() and mem*() function internals at runtime" if !KUNIT_ALL_TESTS
+1 -9
lib/tests/stackinit_kunit.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 3 * Test cases for compiler-based stack variable zeroing via 4 - * -ftrivial-auto-var-init={zero,pattern} or CONFIG_GCC_PLUGIN_STRUCTLEAK*. 4 + * -ftrivial-auto-var-init={zero,pattern}. 5 5 * For example, see: 6 6 * "Running tests with kunit_tool" at Documentation/dev-tools/kunit/start.rst 7 7 * ./tools/testing/kunit/kunit.py run stackinit [--raw_output] \ ··· 375 375 #ifdef CONFIG_INIT_STACK_NONE 376 376 # define USER_PASS XFAIL 377 377 # define BYREF_PASS XFAIL 378 - # define STRONG_PASS XFAIL 379 - #elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER) 380 - # define USER_PASS WANT_SUCCESS 381 - # define BYREF_PASS XFAIL 382 - # define STRONG_PASS XFAIL 383 - #elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) 384 - # define USER_PASS WANT_SUCCESS 385 - # define BYREF_PASS WANT_SUCCESS 386 378 # define STRONG_PASS XFAIL 387 379 #else 388 380 # define USER_PASS WANT_SUCCESS
-6
mm/mm_init.c
··· 2668 2668 stack = "all(pattern)"; 2669 2669 else if (IS_ENABLED(CONFIG_INIT_STACK_ALL_ZERO)) 2670 2670 stack = "all(zero)"; 2671 - else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL)) 2672 - stack = "byref_all(zero)"; 2673 - else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF)) 2674 - stack = "byref(zero)"; 2675 - else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER)) 2676 - stack = "__user(zero)"; 2677 2671 else 2678 2672 stack = "off"; 2679 2673
-14
scripts/Makefile.gcc-plugins
··· 8 8 endif 9 9 export DISABLE_LATENT_ENTROPY_PLUGIN 10 10 11 - gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so 12 - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ 13 - += -fplugin-arg-structleak_plugin-verbose 14 - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \ 15 - += -fplugin-arg-structleak_plugin-byref 16 - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \ 17 - += -fplugin-arg-structleak_plugin-byref-all 18 - ifdef CONFIG_GCC_PLUGIN_STRUCTLEAK 19 - DISABLE_STRUCTLEAK_PLUGIN += -fplugin-arg-structleak_plugin-disable 20 - endif 21 - export DISABLE_STRUCTLEAK_PLUGIN 22 - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ 23 - += -DSTRUCTLEAK_PLUGIN 24 - 25 11 gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so 26 12 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ 27 13 += -DSTACKLEAK_PLUGIN
-257
scripts/gcc-plugins/structleak_plugin.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu> 4 - * 5 - * Note: the choice of the license means that the compilation process is 6 - * NOT 'eligible' as defined by gcc's library exception to the GPL v3, 7 - * but for the kernel it doesn't matter since it doesn't link against 8 - * any of the gcc libraries 9 - * 10 - * gcc plugin to forcibly initialize certain local variables that could 11 - * otherwise leak kernel stack to userland if they aren't properly initialized 12 - * by later code 13 - * 14 - * Homepage: https://pax.grsecurity.net/ 15 - * 16 - * Options: 17 - * -fplugin-arg-structleak_plugin-disable 18 - * -fplugin-arg-structleak_plugin-verbose 19 - * -fplugin-arg-structleak_plugin-byref 20 - * -fplugin-arg-structleak_plugin-byref-all 21 - * 22 - * Usage: 23 - * $ # for 4.5/4.6/C based 4.7 24 - * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c 25 - * $ # for C++ based 4.7/4.8+ 26 - * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c 27 - * $ gcc -fplugin=./structleak_plugin.so test.c -O2 28 - * 29 - * TODO: eliminate redundant initializers 30 - */ 31 - 32 - #include "gcc-common.h" 33 - 34 - /* unused C type flag in all versions 4.5-6 */ 35 - #define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE) 36 - 37 - __visible int plugin_is_GPL_compatible; 38 - 39 - static struct plugin_info structleak_plugin_info = { 40 - .version = PLUGIN_VERSION, 41 - .help = "disable\tdo not activate plugin\n" 42 - "byref\tinit structs passed by reference\n" 43 - "byref-all\tinit anything passed by reference\n" 44 - "verbose\tprint all initialized variables\n", 45 - }; 46 - 47 - #define BYREF_STRUCT 1 48 - #define BYREF_ALL 2 49 - 50 - static bool verbose; 51 - static int byref; 52 - 53 - static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) 54 - { 55 - *no_add_attrs = true; 56 - 57 - /* check for types? for now accept everything linux has to offer */ 58 - if (TREE_CODE(*node) != FIELD_DECL) 59 - return NULL_TREE; 60 - 61 - *no_add_attrs = false; 62 - return NULL_TREE; 63 - } 64 - 65 - static struct attribute_spec user_attr = { }; 66 - 67 - static void register_attributes(void *event_data, void *data) 68 - { 69 - user_attr.name = "user"; 70 - user_attr.handler = handle_user_attribute; 71 - user_attr.affects_type_identity = true; 72 - 73 - register_attribute(&user_attr); 74 - } 75 - 76 - static tree get_field_type(tree field) 77 - { 78 - return strip_array_types(TREE_TYPE(field)); 79 - } 80 - 81 - static bool is_userspace_type(tree type) 82 - { 83 - tree field; 84 - 85 - for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { 86 - tree fieldtype = get_field_type(field); 87 - enum tree_code code = TREE_CODE(fieldtype); 88 - 89 - if (code == RECORD_TYPE || code == UNION_TYPE) 90 - if (is_userspace_type(fieldtype)) 91 - return true; 92 - 93 - if (lookup_attribute("user", DECL_ATTRIBUTES(field))) 94 - return true; 95 - } 96 - return false; 97 - } 98 - 99 - static void finish_type(void *event_data, void *data) 100 - { 101 - tree type = (tree)event_data; 102 - 103 - if (type == NULL_TREE || type == error_mark_node) 104 - return; 105 - 106 - if (TREE_CODE(type) == ENUMERAL_TYPE) 107 - return; 108 - 109 - if (TYPE_USERSPACE(type)) 110 - return; 111 - 112 - if (is_userspace_type(type)) 113 - TYPE_USERSPACE(type) = 1; 114 - } 115 - 116 - static void initialize(tree var) 117 - { 118 - basic_block bb; 119 - gimple_stmt_iterator gsi; 120 - tree initializer; 121 - gimple init_stmt; 122 - tree type; 123 - 124 - /* this is the original entry bb before the forced split */ 125 - bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); 126 - 127 - /* first check if variable is already initialized, warn otherwise */ 128 - for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { 129 - gimple stmt = gsi_stmt(gsi); 130 - tree rhs1; 131 - 132 - /* we're looking for an assignment of a single rhs... */ 133 - if (!gimple_assign_single_p(stmt)) 134 - continue; 135 - rhs1 = gimple_assign_rhs1(stmt); 136 - /* ... of a non-clobbering expression... */ 137 - if (TREE_CLOBBER_P(rhs1)) 138 - continue; 139 - /* ... to our variable... */ 140 - if (gimple_get_lhs(stmt) != var) 141 - continue; 142 - /* if it's an initializer then we're good */ 143 - if (TREE_CODE(rhs1) == CONSTRUCTOR) 144 - return; 145 - } 146 - 147 - /* these aren't the 0days you're looking for */ 148 - if (verbose) 149 - inform(DECL_SOURCE_LOCATION(var), 150 - "%s variable will be forcibly initialized", 151 - (byref && TREE_ADDRESSABLE(var)) ? "byref" 152 - : "userspace"); 153 - 154 - /* build the initializer expression */ 155 - type = TREE_TYPE(var); 156 - if (AGGREGATE_TYPE_P(type)) 157 - initializer = build_constructor(type, NULL); 158 - else 159 - initializer = fold_convert(type, integer_zero_node); 160 - 161 - /* build the initializer stmt */ 162 - init_stmt = gimple_build_assign(var, initializer); 163 - gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 164 - gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT); 165 - update_stmt(init_stmt); 166 - } 167 - 168 - static unsigned int structleak_execute(void) 169 - { 170 - basic_block bb; 171 - tree var; 172 - unsigned int i; 173 - 174 - /* split the first bb where we can put the forced initializers */ 175 - gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 176 - bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); 177 - if (!single_pred_p(bb)) { 178 - split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 179 - gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 180 - } 181 - 182 - /* enumerate all local variables and forcibly initialize our targets */ 183 - FOR_EACH_LOCAL_DECL(cfun, i, var) { 184 - tree type = TREE_TYPE(var); 185 - 186 - gcc_assert(DECL_P(var)); 187 - if (!auto_var_in_fn_p(var, current_function_decl)) 188 - continue; 189 - 190 - /* only care about structure types unless byref-all */ 191 - if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) 192 - continue; 193 - 194 - /* if the type is of interest, examine the variable */ 195 - if (TYPE_USERSPACE(type) || 196 - (byref && TREE_ADDRESSABLE(var))) 197 - initialize(var); 198 - } 199 - 200 - return 0; 201 - } 202 - 203 - #define PASS_NAME structleak 204 - #define NO_GATE 205 - #define PROPERTIES_REQUIRED PROP_cfg 206 - #define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow 207 - #include "gcc-generate-gimple-pass.h" 208 - 209 - __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) 210 - { 211 - int i; 212 - const char * const plugin_name = plugin_info->base_name; 213 - const int argc = plugin_info->argc; 214 - const struct plugin_argument * const argv = plugin_info->argv; 215 - bool enable = true; 216 - 217 - PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE); 218 - 219 - if (!plugin_default_version_check(version, &gcc_version)) { 220 - error(G_("incompatible gcc/plugin versions")); 221 - return 1; 222 - } 223 - 224 - if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { 225 - inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); 226 - enable = false; 227 - } 228 - 229 - for (i = 0; i < argc; ++i) { 230 - if (!strcmp(argv[i].key, "disable")) { 231 - enable = false; 232 - continue; 233 - } 234 - if (!strcmp(argv[i].key, "verbose")) { 235 - verbose = true; 236 - continue; 237 - } 238 - if (!strcmp(argv[i].key, "byref")) { 239 - byref = BYREF_STRUCT; 240 - continue; 241 - } 242 - if (!strcmp(argv[i].key, "byref-all")) { 243 - byref = BYREF_ALL; 244 - continue; 245 - } 246 - error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); 247 - } 248 - 249 - register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info); 250 - if (enable) { 251 - register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info); 252 - register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); 253 - } 254 - register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); 255 - 256 - return 0; 257 - }
-76
security/Kconfig.hardening
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 menu "Kernel hardening options" 3 3 4 - config GCC_PLUGIN_STRUCTLEAK 5 - bool 6 - help 7 - While the kernel is built with warnings enabled for any missed 8 - stack variable initializations, this warning is silenced for 9 - anything passed by reference to another function, under the 10 - occasionally misguided assumption that the function will do 11 - the initialization. As this regularly leads to exploitable 12 - flaws, this plugin is available to identify and zero-initialize 13 - such variables, depending on the chosen level of coverage. 14 - 15 - This plugin was originally ported from grsecurity/PaX. More 16 - information at: 17 - * https://grsecurity.net/ 18 - * https://pax.grsecurity.net/ 19 - 20 4 menu "Memory initialization" 21 5 22 6 config CC_HAS_AUTO_VAR_INIT_PATTERN ··· 20 36 21 37 choice 22 38 prompt "Initialize kernel stack variables at function entry" 23 - default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS 24 39 default INIT_STACK_ALL_PATTERN if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT_PATTERN 25 40 default INIT_STACK_ALL_ZERO if CC_HAS_AUTO_VAR_INIT_ZERO 26 41 default INIT_STACK_NONE ··· 42 59 This leaves the kernel vulnerable to the standard 43 60 classes of uninitialized stack variable exploits 44 61 and information exposures. 45 - 46 - config GCC_PLUGIN_STRUCTLEAK_USER 47 - bool "zero-init structs marked for userspace (weak)" 48 - # Plugin can be removed once the kernel only supports GCC 12+ 49 - depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO 50 - select GCC_PLUGIN_STRUCTLEAK 51 - help 52 - Zero-initialize any structures on the stack containing 53 - a __user attribute. This can prevent some classes of 54 - uninitialized stack variable exploits and information 55 - exposures, like CVE-2013-2141: 56 - https://git.kernel.org/linus/b9e146d8eb3b9eca 57 - 58 - config GCC_PLUGIN_STRUCTLEAK_BYREF 59 - bool "zero-init structs passed by reference (strong)" 60 - # Plugin can be removed once the kernel only supports GCC 12+ 61 - depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO 62 - depends on !(KASAN && KASAN_STACK) 63 - select GCC_PLUGIN_STRUCTLEAK 64 - help 65 - Zero-initialize any structures on the stack that may 66 - be passed by reference and had not already been 67 - explicitly initialized. This can prevent most classes 68 - of uninitialized stack variable exploits and information 69 - exposures, like CVE-2017-1000410: 70 - https://git.kernel.org/linus/06e7e776ca4d3654 71 - 72 - As a side-effect, this keeps a lot of variables on the 73 - stack that can otherwise be optimized out, so combining 74 - this with CONFIG_KASAN_STACK can lead to a stack overflow 75 - and is disallowed. 76 - 77 - config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL 78 - bool "zero-init everything passed by reference (very strong)" 79 - # Plugin can be removed once the kernel only supports GCC 12+ 80 - depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO 81 - depends on !(KASAN && KASAN_STACK) 82 - select GCC_PLUGIN_STRUCTLEAK 83 - help 84 - Zero-initialize any stack variables that may be passed 85 - by reference and had not already been explicitly 86 - initialized. This is intended to eliminate all classes 87 - of uninitialized stack variable exploits and information 88 - exposures. 89 - 90 - As a side-effect, this keeps a lot of variables on the 91 - stack that can otherwise be optimized out, so combining 92 - this with CONFIG_KASAN_STACK can lead to a stack overflow 93 - and is disallowed. 94 62 95 63 config INIT_STACK_ALL_PATTERN 96 64 bool "pattern-init everything (strongest)" ··· 81 147 initialization. 82 148 83 149 endchoice 84 - 85 - config GCC_PLUGIN_STRUCTLEAK_VERBOSE 86 - bool "Report forcefully initialized variables" 87 - depends on GCC_PLUGIN_STRUCTLEAK 88 - depends on !COMPILE_TEST # too noisy 89 - help 90 - This option will cause a warning to be printed each time the 91 - structleak plugin finds a variable it thinks needs to be 92 - initialized. Since not all existing initializers are detected 93 - by the plugin, this can produce false positive warnings. 94 150 95 151 config GCC_PLUGIN_STACKLEAK 96 152 bool "Poison kernel stack before returning from syscalls"