History

Merge tag 'gcc-plugins-v5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull gcc-plugins updates from Kees Cook: "This adds additional type coverage to the existing structleak plugin and adds a large set of selftests to help evaluate stack variable zero-initialization coverage. That can be used to test whatever instrumentation might be performing zero-initialization: either with the structleak plugin or with Clang's coming "-ftrivial-auto-var-init=zero" option. Summary: - Add scalar and array initialization coverage - Refactor Kconfig to make options more clear - Add self-test module for testing automatic initialization" * tag 'gcc-plugins-v5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: lib: Introduce test_stackinit module gcc-plugins: structleak: Generalize to all variable types

Linus Torvalds committed 7 years ago

Commit 2bb99542 parents a39f009 50ceaa96 files · +463 −22Browse files

Showing the changes to scripts (3 of 6 files). Show all

Unified · Split

3 files
  1. scripts/Makefile.gcc-plugins +2 −0
  2. scripts/gcc-plugins/Kconfig +47 −11
  3. scripts/gcc-plugins/structleak_plugin.c +25 −11
scripts/Makefile.gcc-plugins+2−0
@@ -15,6 +15,8 @@ gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so · 14 unmodified lines
1515 gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so
1616 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \
1717 += -fplugin-arg-structleak_plugin-verbose
18+gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \
19+ += -fplugin-arg-structleak_plugin-byref
1820 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \
1921 += -fplugin-arg-structleak_plugin-byref-all
2022 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \
scripts/gcc-plugins/Kconfig+47−11
@@ -67,23 +67,59 @@ config GCC_PLUGIN_LATENT_ENTROPY · 66 unmodified lines
6767 * https://pax.grsecurity.net/
6868
6969 config GCC_PLUGIN_STRUCTLEAK
70− bool "Force initialization of variables containing userspace addresses"
70+ bool "Zero initialize stack variables"
7171 help
72− This plugin zero-initializes any structures containing a
73− __user attribute. This can prevent some classes of information
74− exposures.
75−
76− This plugin was ported from grsecurity/PaX. More information at:
72+ While the kernel is built with warnings enabled for any missed
73+ stack variable initializations, this warning is silenced for
74+ anything passed by reference to another function, under the
75+ occasionally misguided assumption that the function will do
76+ the initialization. As this regularly leads to exploitable
77+ flaws, this plugin is available to identify and zero-initialize
78+ such variables, depending on the chosen level of coverage.
79+
80+ This plugin was originally ported from grsecurity/PaX. More
81+ information at:
7782 * https://grsecurity.net/
7883 * https://pax.grsecurity.net/
7984
80−config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
81− bool "Force initialize all struct type variables passed by reference"
85+choice
86+ prompt "Coverage"
8287 depends on GCC_PLUGIN_STRUCTLEAK
83− depends on !COMPILE_TEST
88+ default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
8489 help
85− Zero initialize any struct type local variable that may be passed by
86− reference without having been initialized.
90+ This chooses the level of coverage over classes of potentially
91+ uninitialized variables. The selected class will be
92+ zero-initialized before use.
93+
94+ config GCC_PLUGIN_STRUCTLEAK_USER
95+ bool "structs marked for userspace"
96+ help
97+ Zero-initialize any structures on the stack containing
98+ a __user attribute. This can prevent some classes of
99+ uninitialized stack variable exploits and information
100+ exposures, like CVE-2013-2141:
101+ https://git.kernel.org/linus/b9e146d8eb3b9eca
102+
103+ config GCC_PLUGIN_STRUCTLEAK_BYREF
104+ bool "structs passed by reference"
105+ help
106+ Zero-initialize any structures on the stack that may
107+ be passed by reference and had not already been
108+ explicitly initialized. This can prevent most classes
109+ of uninitialized stack variable exploits and information
110+ exposures, like CVE-2017-1000410:
111+ https://git.kernel.org/linus/06e7e776ca4d3654
112+
113+ config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
114+ bool "anything passed by reference"
115+ help
116+ Zero-initialize any stack variables that may be passed
117+ by reference and had not already been explicitly
118+ initialized. This is intended to eliminate all classes
119+ of uninitialized stack variable exploits and information
120+ exposures.
121+
122+endchoice
87123
88124 config GCC_PLUGIN_STRUCTLEAK_VERBOSE
89125 bool "Report forcefully initialized variables"
scripts/gcc-plugins/structleak_plugin.c+25−11
@@ -16,6 +16,7 @@ · 15 unmodified lines
1616 * Options:
1717 * -fplugin-arg-structleak_plugin-disable
1818 * -fplugin-arg-structleak_plugin-verbose
19+ * -fplugin-arg-structleak_plugin-byref
1920 * -fplugin-arg-structleak_plugin-byref-all
2021 *
2122 * Usage:
@@ -26,7 +27,6 @@ · 4 unmodified lines
2627 * $ gcc -fplugin=./structleak_plugin.so test.c -O2
2728 *
2829 * TODO: eliminate redundant initializers
29− * increase type coverage
3030 */
3131
3232 #include "gcc-common.h"
@@ -37,13 +37,18 @@ · 4 unmodified lines
3737 __visible int plugin_is_GPL_compatible;
3838
3939 static struct plugin_info structleak_plugin_info = {
40− .version = "201607271510vanilla",
40+ .version = "20190125vanilla",
4141 .help = "disable\tdo not activate plugin\n"
42− "verbose\tprint all initialized variables\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",
4345 };
4446
47+#define BYREF_STRUCT 1
48+#define BYREF_ALL 2
49+
4550 static bool verbose;
46−static bool byref_all;
51+static int byref;
4752
4853 static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
4954 {
@@ -118,6 +123,7 @@ static void initialize(tree var) · 68 unmodified lines
118123 gimple_stmt_iterator gsi;
119124 tree initializer;
120125 gimple init_stmt;
126+ tree type;
121127
122128 /* this is the original entry bb before the forced split */
123129 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
@@ -148,11 +154,15 @@ static void initialize(tree var) · 24 unmodified lines
148154 if (verbose)
149155 inform(DECL_SOURCE_LOCATION(var),
150156 "%s variable will be forcibly initialized",
151− (byref_all && TREE_ADDRESSABLE(var)) ? "byref"
152− : "userspace");
157+ (byref && TREE_ADDRESSABLE(var)) ? "byref"
158+ : "userspace");
153159
154160 /* build the initializer expression */
155− initializer = build_constructor(TREE_TYPE(var), NULL);
161+ type = TREE_TYPE(var);
162+ if (AGGREGATE_TYPE_P(type))
163+ initializer = build_constructor(type, NULL);
164+ else
165+ initializer = fold_convert(type, integer_zero_node);
156166
157167 /* build the initializer stmt */
158168 init_stmt = gimple_build_assign(var, initializer);
@@ -184,13 +194,13 @@ static unsigned int structleak_execute(void) · 25 unmodified lines
184194 if (!auto_var_in_fn_p(var, current_function_decl))
185195 continue;
186196
187− /* only care about structure types */
188− if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
197+ /* only care about structure types unless byref-all */
198+ if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
189199 continue;
190200
191201 /* if the type is of interest, examine the variable */
192202 if (TYPE_USERSPACE(type) ||
193− (byref_all && TREE_ADDRESSABLE(var)))
203+ (byref && TREE_ADDRESSABLE(var)))
194204 initialize(var);
195205 }
196206
@@ -232,8 +242,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc · 35 unmodified lines
232242 verbose = true;
233243 continue;
234244 }
245+ if (!strcmp(argv[i].key, "byref")) {
246+ byref = BYREF_STRUCT;
247+ continue;
248+ }
235249 if (!strcmp(argv[i].key, "byref-all")) {
236− byref_all = true;
250+ byref = BYREF_ALL;
237251 continue;
238252 }
239253 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);