Skip to content

Commit

Permalink
security: allow using Clang's zero initialization for stack variables
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Nick Desaulniers <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Alexander Potapenko <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Reviewed-by: Maciej Żenczykowski <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
  • Loading branch information
ramosian-glider authored and kees committed Jun 16, 2020
1 parent b3a9e3b commit f0fe00d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
13 changes: 11 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -802,11 +802,20 @@ KBUILD_CFLAGS += -fomit-frame-pointer
endif
endif

# Initialize all stack variables with a pattern, if desired.
ifdef CONFIG_INIT_STACK_ALL
# Initialize all stack variables with a 0xAA pattern.
ifdef CONFIG_INIT_STACK_ALL_PATTERN
KBUILD_CFLAGS += -ftrivial-auto-var-init=pattern
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)

ifdef CONFIG_DEBUG_INFO
Expand Down
12 changes: 7 additions & 5 deletions init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,14 +779,16 @@ static void __init report_meminit(void)
{
const char *stack;

if (IS_ENABLED(CONFIG_INIT_STACK_ALL))
stack = "all";
if (IS_ENABLED(CONFIG_INIT_STACK_ALL_PATTERN))
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))
stack = "byref_all";
stack = "byref_all(zero)";
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF))
stack = "byref";
stack = "byref(zero)";
else if (IS_ENABLED(CONFIG_GCC_PLUGIN_STRUCTLEAK_USER))
stack = "__user";
stack = "__user(zero)";
else
stack = "off";

Expand Down
29 changes: 25 additions & 4 deletions security/Kconfig.hardening
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ config GCC_PLUGIN_STRUCTLEAK

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)

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
prompt "Initialize kernel stack variables at function entry"
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
help
This option enables initialization of stack variables at
Expand Down Expand Up @@ -88,16 +91,34 @@ choice
of uninitialized stack variable exploits and information
exposures.

config INIT_STACK_ALL
config INIT_STACK_ALL_PATTERN
bool "0xAA-init everything on the stack (strongest)"
depends on CC_HAS_AUTO_VAR_INIT
depends on CC_HAS_AUTO_VAR_INIT_PATTERN
help
Initializes everything on the stack with a 0xAA
pattern. 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.

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

config GCC_PLUGIN_STRUCTLEAK_VERBOSE
Expand Down

0 comments on commit f0fe00d

Please sign in to comment.