aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/gcc-plugins
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gcc-plugins')
-rw-r--r--scripts/gcc-plugins/Kconfig58
-rw-r--r--scripts/gcc-plugins/structleak_plugin.c36
2 files changed, 72 insertions, 22 deletions
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index d9fd9988ef27..74271dba4f94 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -67,23 +67,59 @@ 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 help 71 help
72 This plugin zero-initializes any structures containing a 72 While the kernel is built with warnings enabled for any missed
73 __user attribute. This can prevent some classes of information 73 stack variable initializations, this warning is silenced for
74 exposures. 74 anything passed by reference to another function, under the
75 75 occasionally misguided assumption that the function will do
76 This plugin was ported from grsecurity/PaX. More information at: 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:
77 * https://grsecurity.net/ 82 * https://grsecurity.net/
78 * https://pax.grsecurity.net/ 83 * https://pax.grsecurity.net/
79 84
80config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL 85choice
81 bool "Force initialize all struct type variables passed by reference" 86 prompt "Coverage"
82 depends on GCC_PLUGIN_STRUCTLEAK 87 depends on GCC_PLUGIN_STRUCTLEAK
83 depends on !COMPILE_TEST 88 default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
84 help 89 help
85 Zero initialize any struct type local variable that may be passed by 90 This chooses the level of coverage over classes of potentially
86 reference without having been initialized. 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
122endchoice
87 123
88config GCC_PLUGIN_STRUCTLEAK_VERBOSE 124config GCC_PLUGIN_STRUCTLEAK_VERBOSE
89 bool "Report forcefully initialized variables" 125 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);