Skip to content

Commit 8779657

Browse files
keesIngo Molnar
authored andcommitted
stackprotector: Introduce CONFIG_CC_STACKPROTECTOR_STRONG
This changes the stack protector config option into a choice of "None", "Regular", and "Strong": CONFIG_CC_STACKPROTECTOR_NONE CONFIG_CC_STACKPROTECTOR_REGULAR CONFIG_CC_STACKPROTECTOR_STRONG "Regular" means the old CONFIG_CC_STACKPROTECTOR=y option. "Strong" is a new mode introduced by this patch. With "Strong" the kernel is built with -fstack-protector-strong (available in gcc 4.9 and later). This option increases the coverage of the stack protector without the heavy performance hit of -fstack-protector-all. For reference, the stack protector options available in gcc are: -fstack-protector-all: Adds the stack-canary saving prefix and stack-canary checking suffix to _all_ function entry and exit. Results in substantial use of stack space for saving the canary for deep stack users (e.g. historically xfs), and measurable (though shockingly still low) performance hit due to all the saving/checking. Really not suitable for sane systems, and was entirely removed as an option from the kernel many years ago. -fstack-protector: Adds the canary save/check to functions that define an 8 (--param=ssp-buffer-size=N, N=8 by default) or more byte local char array. Traditionally, stack overflows happened with string-based manipulations, so this was a way to find those functions. Very few total functions actually get the canary; no measurable performance or size overhead. -fstack-protector-strong Adds the canary for a wider set of functions, since it's not just those with strings that have ultimately been vulnerable to stack-busting. With this superset, more functions end up with a canary, but it still remains small compared to all functions with only a small change in performance. Based on the original design document, a function gets the canary when it contains any of: - local variable's address used as part of the right hand side of an assignment or function argument - local variable is an array (or union containing an array), regardless of array type or length - uses register local variables https://docs.google.com/a/google.com/document/d/1xXBH6rRZue4f296vGt9YQcuLVQHeE516stHwt8M9xyU Find below a comparison of "size" and "objdump" output when built with gcc-4.9 in three configurations: - defconfig 11430641 kernel text size 36110 function bodies - defconfig + CONFIG_CC_STACKPROTECTOR_REGULAR 11468490 kernel text size (+0.33%) 1015 of 36110 functions are stack-protected (2.81%) - defconfig + CONFIG_CC_STACKPROTECTOR_STRONG via this patch 11692790 kernel text size (+2.24%) 7401 of 36110 functions are stack-protected (20.5%) With -strong, ARM's compressed boot code now triggers stack protection, so a static guard was added. Since this is only used during decompression and was never used before, the exposure here is very small. Once it switches to the full kernel, the stack guard is back to normal. Chrome OS has been using -fstack-protector-strong for its kernel builds for the last 8 months with no problems. Signed-off-by: Kees Cook <[email protected]> Cc: Arjan van de Ven <[email protected]> Cc: Michal Marek <[email protected]> Cc: Russell King <[email protected]> Cc: Ralf Baechle <[email protected]> Cc: Paul Mundt <[email protected]> Cc: James Hogan <[email protected]> Cc: Stephen Rothwell <[email protected]> Cc: Shawn Guo <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] [ Improved the changelog and descriptions some more. ] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 19952a9 commit 8779657

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,18 @@ KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
596596
endif
597597

598598
# Handle stack protector mode.
599-
ifdef CONFIG_CC_STACKPROTECTOR
599+
ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
600600
stackp-flag := -fstack-protector
601601
ifeq ($(call cc-option, $(stackp-flag)),)
602602
$(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
603603
-fstack-protector not supported by compiler))
604604
endif
605+
else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
606+
stackp-flag := -fstack-protector-strong
607+
ifeq ($(call cc-option, $(stackp-flag)),)
608+
$(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
609+
-fstack-protector-strong not supported by compiler)
610+
endif
605611
else
606612
# Force off for distro compilers that enable stack protector by default.
607613
stackp-flag := $(call cc-option, -fno-stack-protector)

arch/Kconfig

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,19 +344,64 @@ config HAVE_CC_STACKPROTECTOR
344344
- it has implemented a stack canary (e.g. __stack_chk_guard)
345345

346346
config CC_STACKPROTECTOR
347-
bool "Enable -fstack-protector buffer overflow detection"
347+
def_bool n
348+
help
349+
Set when a stack-protector mode is enabled, so that the build
350+
can enable kernel-side support for the GCC feature.
351+
352+
choice
353+
prompt "Stack Protector buffer overflow detection"
348354
depends on HAVE_CC_STACKPROTECTOR
355+
default CC_STACKPROTECTOR_NONE
349356
help
350-
This option turns on the -fstack-protector GCC feature. This
357+
This option turns on the "stack-protector" GCC feature. This
351358
feature puts, at the beginning of functions, a canary value on
352359
the stack just before the return address, and validates
353360
the value just before actually returning. Stack based buffer
354361
overflows (that need to overwrite this return address) now also
355362
overwrite the canary, which gets detected and the attack is then
356363
neutralized via a kernel panic.
357364

365+
config CC_STACKPROTECTOR_NONE
366+
bool "None"
367+
help
368+
Disable "stack-protector" GCC feature.
369+
370+
config CC_STACKPROTECTOR_REGULAR
371+
bool "Regular"
372+
select CC_STACKPROTECTOR
373+
help
374+
Functions will have the stack-protector canary logic added if they
375+
have an 8-byte or larger character array on the stack.
376+
358377
This feature requires gcc version 4.2 or above, or a distribution
359-
gcc with the feature backported.
378+
gcc with the feature backported ("-fstack-protector").
379+
380+
On an x86 "defconfig" build, this feature adds canary checks to
381+
about 3% of all kernel functions, which increases kernel code size
382+
by about 0.3%.
383+
384+
config CC_STACKPROTECTOR_STRONG
385+
bool "Strong"
386+
select CC_STACKPROTECTOR
387+
help
388+
Functions will have the stack-protector canary logic added in any
389+
of the following conditions:
390+
391+
- local variable's address used as part of the right hand side of an
392+
assignment or function argument
393+
- local variable is an array (or union containing an array),
394+
regardless of array type or length
395+
- uses register local variables
396+
397+
This feature requires gcc version 4.9 or above, or a distribution
398+
gcc with the feature backported ("-fstack-protector-strong").
399+
400+
On an x86 "defconfig" build, this feature adds canary checks to
401+
about 20% of all kernel functions, which increases the kernel code
402+
size by about 2%.
403+
404+
endchoice
360405

361406
config HAVE_CONTEXT_TRACKING
362407
bool

arch/arm/boot/compressed/misc.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ asmlinkage void __div0(void)
127127
error("Attempting division by 0!");
128128
}
129129

130+
unsigned long __stack_chk_guard;
131+
132+
void __stack_chk_guard_setup(void)
133+
{
134+
__stack_chk_guard = 0x000a0dff;
135+
}
136+
137+
void __stack_chk_fail(void)
138+
{
139+
error("stack-protector: Kernel stack is corrupted\n");
140+
}
141+
130142
extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
131143

132144

@@ -137,6 +149,8 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
137149
{
138150
int ret;
139151

152+
__stack_chk_guard_setup();
153+
140154
output_data = (unsigned char *)output_start;
141155
free_mem_ptr = free_mem_ptr_p;
142156
free_mem_end_ptr = free_mem_ptr_end_p;

0 commit comments

Comments
 (0)