aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-08-06 07:06:27 -0400
committerKees Cook <keescook@chromium.org>2017-08-07 14:20:57 -0400
commitf7dd2507893cc3425d3ffc2369559619960befb0 (patch)
tree68c1f03a81c27f5ff0407b51bc2281698d86e56e
parent520eccdfe187591a51ea9ab4c1a024ae4d0f68d9 (diff)
gcc-plugins: structleak: add option to init all vars used as byref args
In the Linux kernel, struct type variables are rarely passed by-value, and so functions that initialize such variables typically take an input reference to the variable rather than returning a value that can subsequently be used in an assignment. If the initalization function is not part of the same compilation unit, the lack of an assignment operation defeats any analysis the compiler can perform as to whether the variable may be used before having been initialized. This means we may end up passing on such variables uninitialized, resulting in potential information leaks. So extend the existing structleak GCC plugin so it will [optionally] apply to all struct type variables that have their address taken at any point, rather than only to variables of struct types that have a __user annotation. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Kees Cook <keescook@chromium.org>
-rw-r--r--arch/Kconfig7
-rw-r--r--scripts/Makefile.gcc-plugins1
-rw-r--r--scripts/gcc-plugins/structleak_plugin.c13
3 files changed, 19 insertions, 2 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 21d0089117fe..0f1621489bf0 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -458,6 +458,13 @@ config GCC_PLUGIN_STRUCTLEAK
458 * https://grsecurity.net/ 458 * https://grsecurity.net/
459 * https://pax.grsecurity.net/ 459 * https://pax.grsecurity.net/
460 460
461config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
462 bool "Force initialize all struct type variables passed by reference"
463 depends on GCC_PLUGIN_STRUCTLEAK
464 help
465 Zero initialize any struct type local variable that may be passed by
466 reference without having been initialized.
467
461config GCC_PLUGIN_STRUCTLEAK_VERBOSE 468config GCC_PLUGIN_STRUCTLEAK_VERBOSE
462 bool "Report forcefully initialized variables" 469 bool "Report forcefully initialized variables"
463 depends on GCC_PLUGIN_STRUCTLEAK 470 depends on GCC_PLUGIN_STRUCTLEAK
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 2e0e2eaa397f..d1f7b0d6be66 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -27,6 +27,7 @@ ifdef CONFIG_GCC_PLUGINS
27 27
28 gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so 28 gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so
29 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose 29 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose
30 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) += -fplugin-arg-structleak_plugin-byref-all
30 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN 31 gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN
31 32
32 gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so 33 gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
index fa3d7a4b26f2..3f8dd4868178 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-all
19 * 20 *
20 * Usage: 21 * Usage:
21 * $ # for 4.5/4.6/C based 4.7 22 * $ # for 4.5/4.6/C based 4.7
@@ -42,6 +43,7 @@ static struct plugin_info structleak_plugin_info = {
42}; 43};
43 44
44static bool verbose; 45static bool verbose;
46static bool byref_all;
45 47
46static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) 48static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
47{ 49{
@@ -150,7 +152,9 @@ static void initialize(tree var)
150 /* these aren't the 0days you're looking for */ 152 /* these aren't the 0days you're looking for */
151 if (verbose) 153 if (verbose)
152 inform(DECL_SOURCE_LOCATION(var), 154 inform(DECL_SOURCE_LOCATION(var),
153 "userspace variable will be forcibly initialized"); 155 "%s variable will be forcibly initialized",
156 (byref_all && TREE_ADDRESSABLE(var)) ? "byref"
157 : "userspace");
154 158
155 /* build the initializer expression */ 159 /* build the initializer expression */
156 initializer = build_constructor(TREE_TYPE(var), NULL); 160 initializer = build_constructor(TREE_TYPE(var), NULL);
@@ -190,7 +194,8 @@ static unsigned int structleak_execute(void)
190 continue; 194 continue;
191 195
192 /* if the type is of interest, examine the variable */ 196 /* if the type is of interest, examine the variable */
193 if (TYPE_USERSPACE(type)) 197 if (TYPE_USERSPACE(type) ||
198 (byref_all && TREE_ADDRESSABLE(var)))
194 initialize(var); 199 initialize(var);
195 } 200 }
196 201
@@ -232,6 +237,10 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc
232 verbose = true; 237 verbose = true;
233 continue; 238 continue;
234 } 239 }
240 if (!strcmp(argv[i].key, "byref-all")) {
241 byref_all = true;
242 continue;
243 }
235 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); 244 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
236 } 245 }
237 246