tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

-ftrivial-auto-var-init in the kernel



tl;dr: Turn on gcc/clang compiler option in kernel to fully initialize
all kernel stack variables, as zero on release builds and nonzero
pattern in current builds, to systematically plug kernel stack memory
disclosure leaks with almost zero performance impact?


BACKGROUND

gcc>=12 and clang>=8 have an option -ftrivial-auto-var-init=zero or
-ftrivial-auto-var-init=pattern that initializes all variables with
automatic storage duration (i.e., local variables in a function) with
all-zero or all-some-pattern (currently 0xfe for gcc but might be
changed, not sure for clang).

https://gcc.gnu.org/onlinedocs/gcc-12.5.0/gcc/Optimize-Options.html#index-ftrivial-auto-var-init
https://releases.llvm.org/8.0.0/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-ftrivial-auto-var-init

The option -ftrivial-auto-var-init=zero for clang>=8<16 also requires
-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang-arg
but in clang>=16 they assented to accepting it as first-class so it
won't be necessary when we next update clang:

https://releases.llvm.org/8.0.0/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang-arg


LIMITATIONS

-ftrivial-auto-var-init does not work for variables declared before
any cases in a switch, like:

	switch (foo) {
		int x;
	case 0:
		...
	}

The warning option -Wtrivial-auto-var-init reports such cases so we
can make sure to avoid them.


SECURITY BENEFIT

Turning this on would essentially eliminate kernel stack disclosure
vulnerabilities.


CODE HYGIENE IMPACT

In gcc, -ftrivial-auto-var-init does not change -Wuninitialized or
-Wanalyzer-use-of-uninitialized-value warnings, so we would still get
alerted if gcc can prove a variable would be affected by this option
in case it appears in code that gets copied & pasted elsewhere -- in
other words, turning this on doesn't reduce our build-time
uninitialized variable hygiene; it just prevents mistakes from turning
into kernel memory disclosure vulnerabilities.

(Not sure offhand if it affects -Wuninitialized warnings in clang; the
clang documentation, as usual, is infuriatingly terse.)


PERFORMANCE IMPACT

There is a small performance impact around 0-5% but these options are
routinely used in large code bases at, e.g., Google and Microsoft
these days -- we would not be the only ones trying out an experiment.
For objects where the compiler can prove they are fully initialized
where they are used, there's no change in code -- so it only will
generally only have an impact on code that isn't obviously safe from
kernel memory disclosure vulnerabilities in the first place, where we
might be inclined to insert an explicit memset anyway.

For Clang in the Linux kernel, the cost of
-ftrivial-auto-var-init=pattern is approximately double the cost of
-ftrivial-auto-var-init=zero -- and in some cases, zero-init actually
made code _faster_ on arm64.  Reference:
https://clangbuiltlinux.github.io/CBL-meetup-2020-slides/glider/Fighting_uninitialized_memory_%40_CBL_Meetup_2020.pdf#page=27
I expect the impact is similar for gcc.  FreeBSD turned this option on
a while ago: <https://reviews.freebsd.org/D40208>.


PROPOSAL

-ftrivial-auto-var-init=pattern is more likely to provoke crashes in
buggy code, while -ftrivial-auto-var-init=zero is more likely to to
lead to silent inaction, since anything used as an array index or
length will tend to lead to loops that run off the end when nonzero
but lead to loops to do nothing when zero.

So I propose that we:

1. Enable -ftrivial-auto-var-init=zero in the kernel for release
   builds with gcc and clang.

2. Enable -ftrivial-auto-var-init=pattern in the kernel for current
   builds with gcc and clang.

3. Enable -Wtrivial-auto-var-init in the kernel for builds with gcc.


Home | Main Index | Thread Index | Old Index