]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Kbuild: remove structleak gcc plugin
authorArnd Bergmann <arnd@arndb.de>
Mon, 7 Apr 2025 19:21:14 +0000 (21:21 +0200)
committerArnd Bergmann <arnd@arndb.de>
Wed, 30 Apr 2025 19:57:09 +0000 (21:57 +0200)
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>
drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
lib/Kconfig.debug
lib/tests/stackinit_kunit.c
mm/mm_init.c
scripts/Makefile.gcc-plugins
scripts/gcc-plugins/structleak_plugin.c [deleted file]
security/Kconfig.hardening

index 4dbf8b88f264f7afcacf2ae8f67704f5a7505341..11d460d2ea1931e242aa34d1378f408c10b2482d 100644 (file)
@@ -86,11 +86,7 @@ struct td028ttec1_panel {
 
 #define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel)
 
-/*
- * noinline_for_stack so we don't get multiple copies of tx_buf
- * on the stack in case of gcc-plugin-structleak
- */
-static int noinline_for_stack
+static int
 jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err)
 {
        struct spi_device *spi = lcd->spi;
index f9051ab610d54358b21d61c141b737bb345b4cee..de19d43666e3b2b874b1d34e77a3d265abbc2ae6 100644 (file)
@@ -2870,9 +2870,7 @@ config STACKINIT_KUNIT_TEST
        help
          Test if the kernel is zero-initializing stack variables and
          padding. Coverage is controlled by compiler flags,
-         CONFIG_INIT_STACK_ALL_PATTERN, CONFIG_INIT_STACK_ALL_ZERO,
-         CONFIG_GCC_PLUGIN_STRUCTLEAK, CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF,
-         or CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL.
+         CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_ALL_ZERO.
 
 config FORTIFY_KUNIT_TEST
        tristate "Test fortified str*() and mem*() function internals at runtime" if !KUNIT_ALL_TESTS
index 63aa78e6f5c1ad02e896a6480cc62b4175b75a86..ff278476977209f4c8b44bdaed022a60579087b3 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Test cases for compiler-based stack variable zeroing via
- * -ftrivial-auto-var-init={zero,pattern} or CONFIG_GCC_PLUGIN_STRUCTLEAK*.
+ * -ftrivial-auto-var-init={zero,pattern}.
  * For example, see:
  * "Running tests with kunit_tool" at Documentation/dev-tools/kunit/start.rst
  *     ./tools/testing/kunit/kunit.py run stackinit [--raw_output] \
@@ -376,14 +376,6 @@ union test_small_end {
 # define USER_PASS     XFAIL
 # define BYREF_PASS    XFAIL
 # define STRONG_PASS   XFAIL
-#elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER)
-# define USER_PASS     WANT_SUCCESS
-# define BYREF_PASS    XFAIL
-# define STRONG_PASS   XFAIL
-#elif defined(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF)
-# define USER_PASS     WANT_SUCCESS
-# define BYREF_PASS    WANT_SUCCESS
-# define STRONG_PASS   XFAIL
 #else
 # define USER_PASS     WANT_SUCCESS
 # define BYREF_PASS    WANT_SUCCESS
index 9659689b8ace01a14934be0919e5bf74546cff54..a1362d2c19e4f8f68c6ffd1418ad5e2ac247c574 100644 (file)
@@ -2668,12 +2668,6 @@ static void __init report_meminit(void)
                stack = "all(pattern)";
        else if (IS_ENABLED(CONFIG_INIT_STACK_ALL_ZERO))
                stack = "all(zero)";
-       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL))
-               stack = "byref_all(zero)";
-       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF))
-               stack = "byref(zero)";
-       else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER))
-               stack = "__user(zero)";
        else
                stack = "off";
 
index e4deaf5fa571d52073dffddfb77fbb6b4db63419..b25f254f9a6806ae45a1bf54bef3be37abdf202a 100644 (file)
@@ -8,20 +8,6 @@ ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
 endif
 export DISABLE_LATENT_ENTROPY_PLUGIN
 
-gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK)     += structleak_plugin.so
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE)      \
-               += -fplugin-arg-structleak_plugin-verbose
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF)                \
-               += -fplugin-arg-structleak_plugin-byref
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL)    \
-               += -fplugin-arg-structleak_plugin-byref-all
-ifdef CONFIG_GCC_PLUGIN_STRUCTLEAK
-    DISABLE_STRUCTLEAK_PLUGIN += -fplugin-arg-structleak_plugin-disable
-endif
-export DISABLE_STRUCTLEAK_PLUGIN
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK)              \
-               += -DSTRUCTLEAK_PLUGIN
-
 gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK)      += stackleak_plugin.so
 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK)               \
                += -DSTACKLEAK_PLUGIN
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
deleted file mode 100644 (file)
index d8c7442..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu>
- *
- * Note: the choice of the license means that the compilation process is
- *       NOT 'eligible' as defined by gcc's library exception to the GPL v3,
- *       but for the kernel it doesn't matter since it doesn't link against
- *       any of the gcc libraries
- *
- * gcc plugin to forcibly initialize certain local variables that could
- * otherwise leak kernel stack to userland if they aren't properly initialized
- * by later code
- *
- * Homepage: https://pax.grsecurity.net/
- *
- * Options:
- * -fplugin-arg-structleak_plugin-disable
- * -fplugin-arg-structleak_plugin-verbose
- * -fplugin-arg-structleak_plugin-byref
- * -fplugin-arg-structleak_plugin-byref-all
- *
- * Usage:
- * $ # for 4.5/4.6/C based 4.7
- * $ 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
- * $ # for C++ based 4.7/4.8+
- * $ 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
- * $ gcc -fplugin=./structleak_plugin.so test.c -O2
- *
- * TODO: eliminate redundant initializers
- */
-
-#include "gcc-common.h"
-
-/* unused C type flag in all versions 4.5-6 */
-#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE)
-
-__visible int plugin_is_GPL_compatible;
-
-static struct plugin_info structleak_plugin_info = {
-       .version        = PLUGIN_VERSION,
-       .help           = "disable\tdo not activate plugin\n"
-                         "byref\tinit structs passed by reference\n"
-                         "byref-all\tinit anything passed by reference\n"
-                         "verbose\tprint all initialized variables\n",
-};
-
-#define BYREF_STRUCT   1
-#define BYREF_ALL      2
-
-static bool verbose;
-static int byref;
-
-static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
-{
-       *no_add_attrs = true;
-
-       /* check for types? for now accept everything linux has to offer */
-       if (TREE_CODE(*node) != FIELD_DECL)
-               return NULL_TREE;
-
-       *no_add_attrs = false;
-       return NULL_TREE;
-}
-
-static struct attribute_spec user_attr = { };
-
-static void register_attributes(void *event_data, void *data)
-{
-       user_attr.name                  = "user";
-       user_attr.handler               = handle_user_attribute;
-       user_attr.affects_type_identity = true;
-
-       register_attribute(&user_attr);
-}
-
-static tree get_field_type(tree field)
-{
-       return strip_array_types(TREE_TYPE(field));
-}
-
-static bool is_userspace_type(tree type)
-{
-       tree field;
-
-       for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) {
-               tree fieldtype = get_field_type(field);
-               enum tree_code code = TREE_CODE(fieldtype);
-
-               if (code == RECORD_TYPE || code == UNION_TYPE)
-                       if (is_userspace_type(fieldtype))
-                               return true;
-
-               if (lookup_attribute("user", DECL_ATTRIBUTES(field)))
-                       return true;
-       }
-       return false;
-}
-
-static void finish_type(void *event_data, void *data)
-{
-       tree type = (tree)event_data;
-
-       if (type == NULL_TREE || type == error_mark_node)
-               return;
-
-       if (TREE_CODE(type) == ENUMERAL_TYPE)
-               return;
-
-       if (TYPE_USERSPACE(type))
-               return;
-
-       if (is_userspace_type(type))
-               TYPE_USERSPACE(type) = 1;
-}
-
-static void initialize(tree var)
-{
-       basic_block bb;
-       gimple_stmt_iterator gsi;
-       tree initializer;
-       gimple init_stmt;
-       tree type;
-
-       /* this is the original entry bb before the forced split */
-       bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
-
-       /* first check if variable is already initialized, warn otherwise */
-       for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
-               gimple stmt = gsi_stmt(gsi);
-               tree rhs1;
-
-               /* we're looking for an assignment of a single rhs... */
-               if (!gimple_assign_single_p(stmt))
-                       continue;
-               rhs1 = gimple_assign_rhs1(stmt);
-               /* ... of a non-clobbering expression... */
-               if (TREE_CLOBBER_P(rhs1))
-                       continue;
-               /* ... to our variable... */
-               if (gimple_get_lhs(stmt) != var)
-                       continue;
-               /* if it's an initializer then we're good */
-               if (TREE_CODE(rhs1) == CONSTRUCTOR)
-                       return;
-       }
-
-       /* these aren't the 0days you're looking for */
-       if (verbose)
-               inform(DECL_SOURCE_LOCATION(var),
-                       "%s variable will be forcibly initialized",
-                       (byref && TREE_ADDRESSABLE(var)) ? "byref"
-                                                        : "userspace");
-
-       /* build the initializer expression */
-       type = TREE_TYPE(var);
-       if (AGGREGATE_TYPE_P(type))
-               initializer = build_constructor(type, NULL);
-       else
-               initializer = fold_convert(type, integer_zero_node);
-
-       /* build the initializer stmt */
-       init_stmt = gimple_build_assign(var, initializer);
-       gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
-       gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT);
-       update_stmt(init_stmt);
-}
-
-static unsigned int structleak_execute(void)
-{
-       basic_block bb;
-       tree var;
-       unsigned int i;
-
-       /* split the first bb where we can put the forced initializers */
-       gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
-       bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
-       if (!single_pred_p(bb)) {
-               split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
-               gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
-       }
-
-       /* enumerate all local variables and forcibly initialize our targets */
-       FOR_EACH_LOCAL_DECL(cfun, i, var) {
-               tree type = TREE_TYPE(var);
-
-               gcc_assert(DECL_P(var));
-               if (!auto_var_in_fn_p(var, current_function_decl))
-                       continue;
-
-               /* only care about structure types unless byref-all */
-               if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
-                       continue;
-
-               /* if the type is of interest, examine the variable */
-               if (TYPE_USERSPACE(type) ||
-                   (byref && TREE_ADDRESSABLE(var)))
-                       initialize(var);
-       }
-
-       return 0;
-}
-
-#define PASS_NAME structleak
-#define NO_GATE
-#define PROPERTIES_REQUIRED PROP_cfg
-#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
-#include "gcc-generate-gimple-pass.h"
-
-__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
-{
-       int i;
-       const char * const plugin_name = plugin_info->base_name;
-       const int argc = plugin_info->argc;
-       const struct plugin_argument * const argv = plugin_info->argv;
-       bool enable = true;
-
-       PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE);
-
-       if (!plugin_default_version_check(version, &gcc_version)) {
-               error(G_("incompatible gcc/plugin versions"));
-               return 1;
-       }
-
-       if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
-               inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
-               enable = false;
-       }
-
-       for (i = 0; i < argc; ++i) {
-               if (!strcmp(argv[i].key, "disable")) {
-                       enable = false;
-                       continue;
-               }
-               if (!strcmp(argv[i].key, "verbose")) {
-                       verbose = true;
-                       continue;
-               }
-               if (!strcmp(argv[i].key, "byref")) {
-                       byref = BYREF_STRUCT;
-                       continue;
-               }
-               if (!strcmp(argv[i].key, "byref-all")) {
-                       byref = BYREF_ALL;
-                       continue;
-               }
-               error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
-       }
-
-       register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info);
-       if (enable) {
-               register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info);
-               register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
-       }
-       register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
-
-       return 0;
-}
index 3fe9d7b945c43e86d97a1b3f0868cf763a7ede26..bdb4667406eb7cdab5c8bed1d4b5813ae2a84eb5 100644 (file)
@@ -1,22 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "Kernel hardening options"
 
-config GCC_PLUGIN_STRUCTLEAK
-       bool
-       help
-         While the kernel is built with warnings enabled for any missed
-         stack variable initializations, this warning is silenced for
-         anything passed by reference to another function, under the
-         occasionally misguided assumption that the function will do
-         the initialization. As this regularly leads to exploitable
-         flaws, this plugin is available to identify and zero-initialize
-         such variables, depending on the chosen level of coverage.
-
-         This plugin was originally ported from grsecurity/PaX. More
-         information at:
-          * https://grsecurity.net/
-          * https://pax.grsecurity.net/
-
 menu "Memory initialization"
 
 config CC_HAS_AUTO_VAR_INIT_PATTERN
@@ -36,7 +20,6 @@ config CC_HAS_AUTO_VAR_INIT_ZERO
 
 choice
        prompt "Initialize kernel stack variables at function entry"
-       default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS
        default INIT_STACK_ALL_PATTERN if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT_PATTERN
        default INIT_STACK_ALL_ZERO if CC_HAS_AUTO_VAR_INIT_ZERO
        default INIT_STACK_NONE
@@ -60,55 +43,6 @@ choice
                  classes of uninitialized stack variable exploits
                  and information exposures.
 
-       config GCC_PLUGIN_STRUCTLEAK_USER
-               bool "zero-init structs marked for userspace (weak)"
-               # Plugin can be removed once the kernel only supports GCC 12+
-               depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO
-               select GCC_PLUGIN_STRUCTLEAK
-               help
-                 Zero-initialize any structures on the stack containing
-                 a __user attribute. This can prevent some classes of
-                 uninitialized stack variable exploits and information
-                 exposures, like CVE-2013-2141:
-                 https://git.kernel.org/linus/b9e146d8eb3b9eca
-
-       config GCC_PLUGIN_STRUCTLEAK_BYREF
-               bool "zero-init structs passed by reference (strong)"
-               # Plugin can be removed once the kernel only supports GCC 12+
-               depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO
-               depends on !(KASAN && KASAN_STACK)
-               select GCC_PLUGIN_STRUCTLEAK
-               help
-                 Zero-initialize any structures on the stack that may
-                 be passed by reference and had not already been
-                 explicitly initialized. This can prevent most classes
-                 of uninitialized stack variable exploits and information
-                 exposures, like CVE-2017-1000410:
-                 https://git.kernel.org/linus/06e7e776ca4d3654
-
-                 As a side-effect, this keeps a lot of variables on the
-                 stack that can otherwise be optimized out, so combining
-                 this with CONFIG_KASAN_STACK can lead to a stack overflow
-                 and is disallowed.
-
-       config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
-               bool "zero-init everything passed by reference (very strong)"
-               # Plugin can be removed once the kernel only supports GCC 12+
-               depends on GCC_PLUGINS && !CC_HAS_AUTO_VAR_INIT_ZERO
-               depends on !(KASAN && KASAN_STACK)
-               select GCC_PLUGIN_STRUCTLEAK
-               help
-                 Zero-initialize any stack variables that may be passed
-                 by reference and had not already been explicitly
-                 initialized. This is intended to eliminate all classes
-                 of uninitialized stack variable exploits and information
-                 exposures.
-
-                 As a side-effect, this keeps a lot of variables on the
-                 stack that can otherwise be optimized out, so combining
-                 this with CONFIG_KASAN_STACK can lead to a stack overflow
-                 and is disallowed.
-
        config INIT_STACK_ALL_PATTERN
                bool "pattern-init everything (strongest)"
                depends on CC_HAS_AUTO_VAR_INIT_PATTERN
@@ -148,16 +82,6 @@ choice
 
 endchoice
 
-config GCC_PLUGIN_STRUCTLEAK_VERBOSE
-       bool "Report forcefully initialized variables"
-       depends on GCC_PLUGIN_STRUCTLEAK
-       depends on !COMPILE_TEST        # too noisy
-       help
-         This option will cause a warning to be printed each time the
-         structleak plugin finds a variable it thinks needs to be
-         initialized. Since not all existing initializers are detected
-         by the plugin, this can produce false positive warnings.
-
 config GCC_PLUGIN_STACKLEAK
        bool "Poison kernel stack before returning from syscalls"
        depends on GCC_PLUGINS