diff options
Diffstat (limited to 'scripts/gcc-plugins')
| -rw-r--r-- | scripts/gcc-plugins/Kconfig | 62 | ||||
| -rw-r--r-- | scripts/gcc-plugins/structleak_plugin.c | 36 | 
2 files changed, 72 insertions, 26 deletions
| diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig index d45f7f36b859..74271dba4f94 100644 --- a/scripts/gcc-plugins/Kconfig +++ b/scripts/gcc-plugins/Kconfig @@ -67,27 +67,59 @@ config GCC_PLUGIN_LATENT_ENTROPY  	   * https://pax.grsecurity.net/  config GCC_PLUGIN_STRUCTLEAK -	bool "Force initialization of variables containing userspace addresses" -	# Currently STRUCTLEAK inserts initialization out of live scope of -	# variables from KASAN point of view. This leads to KASAN false -	# positive reports. Prohibit this combination for now. -	depends on !KASAN_EXTRA +	bool "Zero initialize stack variables"  	help -	  This plugin zero-initializes any structures containing a -	  __user attribute. This can prevent some classes of information -	  exposures. - -	  This plugin was ported from grsecurity/PaX. More information at: +	  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/ -config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL -	bool "Force initialize all struct type variables passed by reference" +choice +	prompt "Coverage"  	depends on GCC_PLUGIN_STRUCTLEAK -	depends on !COMPILE_TEST +	default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL  	help -	  Zero initialize any struct type local variable that may be passed by -	  reference without having been initialized. +	  This chooses the level of coverage over classes of potentially +	  uninitialized variables. The selected class will be +	  zero-initialized before use. + +	config GCC_PLUGIN_STRUCTLEAK_USER +		bool "structs marked for userspace" +		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 "structs passed by reference" +		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 + +	config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL +		bool "anything passed by reference" +		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. + +endchoice  config GCC_PLUGIN_STRUCTLEAK_VERBOSE  	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 @@   * Options:   * -fplugin-arg-structleak_plugin-disable   * -fplugin-arg-structleak_plugin-verbose + * -fplugin-arg-structleak_plugin-byref   * -fplugin-arg-structleak_plugin-byref-all   *   * Usage: @@ -26,7 +27,6 @@   * $ gcc -fplugin=./structleak_plugin.so test.c -O2   *   * TODO: eliminate redundant initializers - *       increase type coverage   */  #include "gcc-common.h" @@ -37,13 +37,18 @@  __visible int plugin_is_GPL_compatible;  static struct plugin_info structleak_plugin_info = { -	.version	= "201607271510vanilla", +	.version	= "20190125vanilla",  	.help		= "disable\tdo not activate plugin\n" -			   "verbose\tprint all initialized variables\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 bool byref_all; +static int byref;  static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)  { @@ -118,6 +123,7 @@ static void initialize(tree var)  	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)); @@ -148,11 +154,15 @@ static void initialize(tree var)  	if (verbose)  		inform(DECL_SOURCE_LOCATION(var),  			"%s variable will be forcibly initialized", -			(byref_all && TREE_ADDRESSABLE(var)) ? "byref" -							     : "userspace"); +			(byref && TREE_ADDRESSABLE(var)) ? "byref" +							 : "userspace");  	/* build the initializer expression */ -	initializer = build_constructor(TREE_TYPE(var), NULL); +	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); @@ -184,13 +194,13 @@ static unsigned int structleak_execute(void)  		if (!auto_var_in_fn_p(var, current_function_decl))  			continue; -		/* only care about structure types */ -		if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) +		/* 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_all && TREE_ADDRESSABLE(var))) +		    (byref && TREE_ADDRESSABLE(var)))  			initialize(var);  	} @@ -232,8 +242,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc  			verbose = true;  			continue;  		} +		if (!strcmp(argv[i].key, "byref")) { +			byref = BYREF_STRUCT; +			continue; +		}  		if (!strcmp(argv[i].key, "byref-all")) { -			byref_all = true; +			byref = BYREF_ALL;  			continue;  		}  		error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); | 
