aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scripts/Makefile.gcc-plugins2
-rw-r--r--scripts/gcc-plugins/Kconfig58
-rw-r--r--scripts/gcc-plugins/structleak_plugin.c36
3 files changed, 74 insertions, 22 deletions
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 35042d96cf5d..5f7df50cfe7a 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -15,6 +15,8 @@ gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so
15gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so 15gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so
16gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ 16gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \
17 += -fplugin-arg-structleak_plugin-verbose 17 += -fplugin-arg-structleak_plugin-verbose
18gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \
19 += -fplugin-arg-structleak_plugin-byref
18gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \ 20gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \
19 += -fplugin-arg-structleak_plugin-byref-all 21 += -fplugin-arg-structleak_plugin-byref-all
20gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ 22gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index d45f7f36b859..d0cc92e48f6f 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -67,27 +67,63 @@ config GCC_PLUGIN_LATENT_ENTROPY
67 * https://pax.grsecurity.net/ 67 * https://pax.grsecurity.net/
68 68
69config GCC_PLUGIN_STRUCTLEAK 69config GCC_PLUGIN_STRUCTLEAK
70 bool "Force initialization of variables containing userspace addresses" 70 bool "Zero initialize stack variables"
71 # Currently STRUCTLEAK inserts initialization out of live scope of 71 # Currently STRUCTLEAK inserts initialization out of live scope of
72 # variables from KASAN point of view. This leads to KASAN false 72 # variables from KASAN point of view. This leads to KASAN false
73 # positive reports. Prohibit this combination for now. 73 # positive reports. Prohibit this combination for now.
74 depends on !KASAN_EXTRA 74 depends on !KASAN_EXTRA
75 help 75 help
76 This plugin zero-initializes any structures containing a 76 While the kernel is built with warnings enabled for any missed
77 __user attribute. This can prevent some classes of information 77 stack variable initializations, this warning is silenced for
78 exposures. 78 anything passed by reference to another function, under the
79 79 occasionally misguided assumption that the function will do
80 This plugin was ported from grsecurity/PaX. More information at: 80 the initialization. As this regularly leads to exploitable
81 flaws, this plugin is available to identify and zero-initialize
82 such variables, depending on the chosen level of coverage.
83
84 This plugin was originally ported from grsecurity/PaX. More
85 information at:
81 * https://grsecurity.net/ 86 * https://grsecurity.net/
82 * https://pax.grsecurity.net/ 87 * https://pax.grsecurity.net/
83 88
84config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL 89choice
85 bool "Force initialize all struct type variables passed by reference" 90 prompt "Coverage"
86 depends on GCC_PLUGIN_STRUCTLEAK 91 depends on GCC_PLUGIN_STRUCTLEAK
87 depends on !COMPILE_TEST 92 default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
88 help 93 help
89 Zero initialize any struct type local variable that may be passed by 94 This chooses the level of coverage over classes of potentially
90 reference without having been initialized. 95 uninitialized variables. The selected class will be
96 zero-initialized before use.
97
98 config GCC_PLUGIN_STRUCTLEAK_USER
99 bool "structs marked for userspace"
100 help
101 Zero-initialize any structures on the stack containing
102 a __user attribute. This can prevent some classes of
103 uninitialized stack variable exploits and information
104 exposures, like CVE-2013-2141:
105 https://git.kernel.org/linus/b9e146d8eb3b9eca
106
107 config GCC_PLUGIN_STRUCTLEAK_BYREF
108 bool "structs passed by reference"
109 help
110 Zero-initialize any structures on the stack that may
111 be passed by reference and had not already been
112 explicitly initialized. This can prevent most classes
113 of uninitialized stack variable exploits and information
114 exposures, like CVE-2017-1000410:
115 https://git.kernel.org/linus/06e7e776ca4d3654
116
117 config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
118 bool "anything passed by reference"
119 help
120 Zero-initialize any stack variables that may be passed
121 by reference and had not already been explicitly
122 initialized. This is intended to eliminate all classes
123 of uninitialized stack variable exploits and information
124 exposures.
125
126endchoice
91 127
92config GCC_PLUGIN_STRUCTLEAK_VERBOSE 128config GCC_PLUGIN_STRUCTLEAK_VERBOSE
93 bool "Report forcefully initialized variables" 129 bool "Report forcefully initialized variables"
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
index 10292f791e99..e89be8f5c859 100644
--- a/scripts/gcc-plugins/structleak_plugin.c
+++ b/scripts/gcc-plugins/structleak_plugin.c
@@ -16,6 +16,7 @@
16 * Options: 16 * Options:
17 * -fplugin-arg-structleak_plugin-disable 17 * -fplugin-arg-structleak_plugin-disable
18 * -fplugin-arg-structleak_plugin-verbose 18 * -fplugin-arg-structleak_plugin-verbose
19 * -fplugin-arg-structleak_plugin-byref
19 * -fplugin-arg-structleak_plugin-byref-all 20 * -fplugin-arg-structleak_plugin-byref-all
20 * 21 *
21 * Usage: 22 * Usage:
@@ -26,7 +27,6 @@
26 * $ gcc -fplugin=./structleak_plugin.so test.c -O2 27 * $ gcc -fplugin=./structleak_plugin.so test.c -O2
27 * 28 *
28 * TODO: eliminate redundant initializers 29 * TODO: eliminate redundant initializers
29 * increase type coverage
30 */ 30 */
31 31
32#include "gcc-common.h" 32#include "gcc-common.h"
@@ -37,13 +37,18 @@
37__visible int plugin_is_GPL_compatible; 37__visible int plugin_is_GPL_compatible;
38 38
39static struct plugin_info structleak_plugin_info = { 39static struct plugin_info structleak_plugin_info = {
40 .version = "201607271510vanilla", 40 .version = "20190125vanilla",
41 .help = "disable\tdo not activate plugin\n" 41 .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",
43}; 45};
44 46
47#define BYREF_STRUCT 1
48#define BYREF_ALL 2
49
45static bool verbose; 50static bool verbose;
46static bool byref_all; 51static int byref;
47 52
48static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) 53static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
49{ 54{
@@ -118,6 +123,7 @@ static void initialize(tree var)
118 gimple_stmt_iterator gsi; 123 gimple_stmt_iterator gsi;
119 tree initializer; 124 tree initializer;
120 gimple init_stmt; 125 gimple init_stmt;
126 tree type;
121 127
122 /* this is the original entry bb before the forced split */ 128 /* this is the original entry bb before the forced split */
123 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); 129 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
@@ -148,11 +154,15 @@ static void initialize(tree var)
148 if (verbose) 154 if (verbose)
149 inform(DECL_SOURCE_LOCATION(var), 155 inform(DECL_SOURCE_LOCATION(var),
150 "%s variable will be forcibly initialized", 156 "%s variable will be forcibly initialized",
151 (byref_all && TREE_ADDRESSABLE(var)) ? "byref" 157 (byref && TREE_ADDRESSABLE(var)) ? "byref"
152 : "userspace"); 158 : "userspace");
153 159
154 /* build the initializer expression */ 160 /* 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);
156 166
157 /* build the initializer stmt */ 167 /* build the initializer stmt */
158 init_stmt = gimple_build_assign(var, initializer); 168 init_stmt = gimple_build_assign(var, initializer);
@@ -184,13 +194,13 @@ static unsigned int structleak_execute(void)
184 if (!auto_var_in_fn_p(var, current_function_decl)) 194 if (!auto_var_in_fn_p(var, current_function_decl))
185 continue; 195 continue;
186 196
187 /* only care about structure types */ 197 /* only care about structure types unless byref-all */
188 if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) 198 if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
189 continue; 199 continue;
190 200
191 /* if the type is of interest, examine the variable */ 201 /* if the type is of interest, examine the variable */
192 if (TYPE_USERSPACE(type) || 202 if (TYPE_USERSPACE(type) ||
193 (byref_all && TREE_ADDRESSABLE(var))) 203 (byref && TREE_ADDRESSABLE(var)))
194 initialize(var); 204 initialize(var);
195 } 205 }
196 206
@@ -232,8 +242,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc
232 verbose = true; 242 verbose = true;
233 continue; 243 continue;
234 } 244 }
245 if (!strcmp(argv[i].key, "byref")) {
246 byref = BYREF_STRUCT;
247 continue;
248 }
235 if (!strcmp(argv[i].key, "byref-all")) { 249 if (!strcmp(argv[i].key, "byref-all")) {
236 byref_all = true; 250 byref = BYREF_ALL;
237 continue; 251 continue;
238 } 252 }
239 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); 253 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);