security: allow using Clang's zero initialization for stack variables
In addition to -ftrivial-auto-var-init=pattern (used by CONFIG_INIT_STACK_ALL now) Clang also supports zero initialization for locals enabled by -ftrivial-auto-var-init=zero. The future of this flag is still being debated (see https://bugs.llvm.org/show_bug.cgi?id=45497). Right now it is guarded by another flag, -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang, which means it may not be supported by future Clang releases. Another possible resolution is that -ftrivial-auto-var-init=zero will persist (as certain users have already started depending on it), but the name of the guard flag will change. In the meantime, zero initialization has proven itself as a good production mitigation measure against uninitialized locals. Unlike pattern initialization, which has a higher chance of triggering existing bugs, zero initialization provides safe defaults for strings, pointers, indexes, and sizes. On the other hand, pattern initialization remains safer for return values. Chrome OS and Android are moving to using zero initialization for production builds. Performance-wise, the difference between pattern and zero initialization is usually negligible, although the generated code for zero initialization is more compact. This patch renames CONFIG_INIT_STACK_ALL to CONFIG_INIT_STACK_ALL_PATTERN and introduces another config option, CONFIG_INIT_STACK_ALL_ZERO, that enables zero initialization for locals if the corresponding flags are supported by Clang. Cc: Kees Cook <keescook@chromium.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Alexander Potapenko <glider@google.com> Link: https://lore.kernel.org/r/20200616083435.223038-1-glider@google.com Reviewed-by: Maciej Żenczykowski <maze@google.com> Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
b3a9e3b962
commit
f0fe00d497
13
Makefile
13
Makefile
|
@ -802,11 +802,20 @@ KBUILD_CFLAGS += -fomit-frame-pointer
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Initialize all stack variables with a pattern, if desired.
|
# Initialize all stack variables with a 0xAA pattern.
|
||||||
ifdef CONFIG_INIT_STACK_ALL
|
ifdef CONFIG_INIT_STACK_ALL_PATTERN
|
||||||
KBUILD_CFLAGS += -ftrivial-auto-var-init=pattern
|
KBUILD_CFLAGS += -ftrivial-auto-var-init=pattern
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Initialize all stack variables with a zero value.
|
||||||
|
ifdef CONFIG_INIT_STACK_ALL_ZERO
|
||||||
|
# Future support for zero initialization is still being debated, see
|
||||||
|
# https://bugs.llvm.org/show_bug.cgi?id=45497. These flags are subject to being
|
||||||
|
# renamed or dropped.
|
||||||
|
KBUILD_CFLAGS += -ftrivial-auto-var-init=zero
|
||||||
|
KBUILD_CFLAGS += -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
|
||||||
|
endif
|
||||||
|
|
||||||
DEBUG_CFLAGS := $(call cc-option, -fno-var-tracking-assignments)
|
DEBUG_CFLAGS := $(call cc-option, -fno-var-tracking-assignments)
|
||||||
|
|
||||||
ifdef CONFIG_DEBUG_INFO
|
ifdef CONFIG_DEBUG_INFO
|
||||||
|
|
12
init/main.c
12
init/main.c
|
@ -779,14 +779,16 @@ static void __init report_meminit(void)
|
||||||
{
|
{
|
||||||
const char *stack;
|
const char *stack;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_INIT_STACK_ALL))
|
if (IS_ENABLED(CONFIG_INIT_STACK_ALL_PATTERN))
|
||||||
stack = "all";
|
stack = "all(pattern)";
|
||||||
|
else if (IS_ENABLED(CONFIG_INIT_STACK_ALL_ZERO))
|
||||||
|
stack = "all(zero)";
|
||||||
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL))
|
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL))
|
||||||
stack = "byref_all";
|
stack = "byref_all(zero)";
|
||||||
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF))
|
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF))
|
||||||
stack = "byref";
|
stack = "byref(zero)";
|
||||||
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER))
|
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER))
|
||||||
stack = "__user";
|
stack = "__user(zero)";
|
||||||
else
|
else
|
||||||
stack = "off";
|
stack = "off";
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,16 @@ config GCC_PLUGIN_STRUCTLEAK
|
||||||
|
|
||||||
menu "Memory initialization"
|
menu "Memory initialization"
|
||||||
|
|
||||||
config CC_HAS_AUTO_VAR_INIT
|
config CC_HAS_AUTO_VAR_INIT_PATTERN
|
||||||
def_bool $(cc-option,-ftrivial-auto-var-init=pattern)
|
def_bool $(cc-option,-ftrivial-auto-var-init=pattern)
|
||||||
|
|
||||||
|
config CC_HAS_AUTO_VAR_INIT_ZERO
|
||||||
|
def_bool $(cc-option,-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang)
|
||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "Initialize kernel stack variables at function entry"
|
prompt "Initialize kernel stack variables at function entry"
|
||||||
default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS
|
default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS
|
||||||
default INIT_STACK_ALL if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT
|
default INIT_STACK_ALL_PATTERN if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT_PATTERN
|
||||||
default INIT_STACK_NONE
|
default INIT_STACK_NONE
|
||||||
help
|
help
|
||||||
This option enables initialization of stack variables at
|
This option enables initialization of stack variables at
|
||||||
|
@ -88,9 +91,9 @@ choice
|
||||||
of uninitialized stack variable exploits and information
|
of uninitialized stack variable exploits and information
|
||||||
exposures.
|
exposures.
|
||||||
|
|
||||||
config INIT_STACK_ALL
|
config INIT_STACK_ALL_PATTERN
|
||||||
bool "0xAA-init everything on the stack (strongest)"
|
bool "0xAA-init everything on the stack (strongest)"
|
||||||
depends on CC_HAS_AUTO_VAR_INIT
|
depends on CC_HAS_AUTO_VAR_INIT_PATTERN
|
||||||
help
|
help
|
||||||
Initializes everything on the stack with a 0xAA
|
Initializes everything on the stack with a 0xAA
|
||||||
pattern. This is intended to eliminate all classes
|
pattern. This is intended to eliminate all classes
|
||||||
|
@ -98,6 +101,24 @@ choice
|
||||||
exposures, even variables that were warned to have been
|
exposures, even variables that were warned to have been
|
||||||
left uninitialized.
|
left uninitialized.
|
||||||
|
|
||||||
|
Pattern initialization is known to provoke many existing bugs
|
||||||
|
related to uninitialized locals, e.g. pointers receive
|
||||||
|
non-NULL values, buffer sizes and indices are very big.
|
||||||
|
|
||||||
|
config INIT_STACK_ALL_ZERO
|
||||||
|
bool "zero-init everything on the stack (strongest and safest)"
|
||||||
|
depends on CC_HAS_AUTO_VAR_INIT_ZERO
|
||||||
|
help
|
||||||
|
Initializes everything on the stack with a zero
|
||||||
|
value. This is intended to eliminate all classes
|
||||||
|
of uninitialized stack variable exploits and information
|
||||||
|
exposures, even variables that were warned to have been
|
||||||
|
left uninitialized.
|
||||||
|
|
||||||
|
Zero initialization provides safe defaults for strings,
|
||||||
|
pointers, indices and sizes, and is therefore
|
||||||
|
more suitable as a security mitigation measure.
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config GCC_PLUGIN_STRUCTLEAK_VERBOSE
|
config GCC_PLUGIN_STRUCTLEAK_VERBOSE
|
||||||
|
|
Loading…
Reference in New Issue