Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

stack-protector: test compiler capability in Kconfig and drop AUTO mode

Move the test for -fstack-protector(-strong) option to Kconfig.

If the compiler does not support the option, the corresponding menu
is automatically hidden. If STRONG is not supported, it will fall
back to REGULAR. If REGULAR is not supported, it will be disabled.
This means, AUTO is implicitly handled by the dependency solver of
Kconfig, hence removed.

I also turned the 'choice' into only two boolean symbols. The use of
'choice' is not a good idea here, because all of all{yes,mod,no}config
would choose the first visible value, while we want allnoconfig to
disable as many features as possible.

X86 has additional shell scripts in case the compiler supports those
options, but generates broken code. I added CC_HAS_SANE_STACKPROTECTOR
to test this. I had to add -m32 to gcc-x86_32-has-stack-protector.sh
to make it work correctly.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Acked-by: Kees Cook <keescook@chromium.org>

+28 -120
+6 -87
Makefile
··· 686 686 KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN}) 687 687 endif 688 688 689 - # This selects the stack protector compiler flag. Testing it is delayed 690 - # until after .config has been reprocessed, in the prepare-compiler-check 691 - # target. 692 - ifdef CONFIG_CC_STACKPROTECTOR_AUTO 693 - stackp-flag := $(call cc-option,-fstack-protector-strong,$(call cc-option,-fstack-protector)) 694 - stackp-name := AUTO 695 - else 696 - ifdef CONFIG_CC_STACKPROTECTOR_REGULAR 697 - stackp-flag := -fstack-protector 698 - stackp-name := REGULAR 699 - else 700 - ifdef CONFIG_CC_STACKPROTECTOR_STRONG 701 - stackp-flag := -fstack-protector-strong 702 - stackp-name := STRONG 703 - else 704 - # If either there is no stack protector for this architecture or 705 - # CONFIG_CC_STACKPROTECTOR_NONE is selected, we're done, and $(stackp-name) 706 - # is empty, skipping all remaining stack protector tests. 707 - # 708 - # Force off for distro compilers that enable stack protector by default. 709 - KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) 710 - endif 711 - endif 712 - endif 713 - # Find arch-specific stack protector compiler sanity-checking script. 714 - ifdef stackp-name 715 - ifneq ($(stackp-flag),) 716 - stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh 717 - stackp-check := $(wildcard $(stackp-path)) 718 - # If the wildcard test matches a test script, run it to check functionality. 719 - ifdef stackp-check 720 - ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) 721 - stackp-broken := y 722 - endif 723 - endif 724 - ifndef stackp-broken 725 - # If the stack protector is functional, enable code that depends on it. 726 - KBUILD_CPPFLAGS += -DCONFIG_CC_STACKPROTECTOR 727 - # Either we've already detected the flag (for AUTO) or we'll fail the 728 - # build in the prepare-compiler-check rule (for specific flag). 729 - KBUILD_CFLAGS += $(stackp-flag) 730 - else 731 - # We have to make sure stack protector is unconditionally disabled if 732 - # the compiler is broken (in case we're going to continue the build in 733 - # AUTO mode). 734 - KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) 735 - endif 736 - endif 737 - endif 689 + stackp-flags-$(CONFIG_CC_HAS_STACKPROTECTOR_NONE) := -fno-stack-protector 690 + stackp-flags-$(CONFIG_CC_STACKPROTECTOR) := -fstack-protector 691 + stackp-flags-$(CONFIG_CC_STACKPROTECTOR_STRONG) := -fstack-protector-strong 692 + 693 + KBUILD_CFLAGS += $(stackp-flags-y) 738 694 739 695 ifeq ($(cc-name),clang) 740 696 KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) ··· 1074 1118 # prepare2 creates a makefile if using a separate output directory. 1075 1119 # From this point forward, .config has been reprocessed, so any rules 1076 1120 # that need to depend on updated CONFIG_* values can be checked here. 1077 - prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic 1121 + prepare2: prepare3 outputmakefile asm-generic 1078 1122 1079 1123 prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h \ 1080 1124 include/config/auto.conf ··· 1099 1143 1100 1144 PHONY += prepare-objtool 1101 1145 prepare-objtool: $(objtool_target) 1102 - 1103 - # Check for CONFIG flags that require compiler support. Abort the build 1104 - # after .config has been processed, but before the kernel build starts. 1105 - # 1106 - # For security-sensitive CONFIG options, we don't want to fallback and/or 1107 - # silently change which compiler flags will be used, since that leads to 1108 - # producing kernels with different security feature characteristics 1109 - # depending on the compiler used. (For example, "But I selected 1110 - # CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!") 1111 - PHONY += prepare-compiler-check 1112 - prepare-compiler-check: FORCE 1113 - # Make sure compiler supports requested stack protector flag. 1114 - ifdef stackp-name 1115 - # Warn about CONFIG_CC_STACKPROTECTOR_AUTO having found no option. 1116 - ifeq ($(stackp-flag),) 1117 - @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ 1118 - Compiler does not support any known stack-protector >&2 1119 - else 1120 - # Fail if specifically requested stack protector is missing. 1121 - ifeq ($(call cc-option, $(stackp-flag)),) 1122 - @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ 1123 - $(stackp-flag) not supported by compiler >&2 && exit 1 1124 - endif 1125 - endif 1126 - endif 1127 - # Make sure compiler does not have buggy stack-protector support. If a 1128 - # specific stack-protector was requested, fail the build, otherwise warn. 1129 - ifdef stackp-broken 1130 - ifeq ($(stackp-name),AUTO) 1131 - @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ 1132 - $(stackp-flag) available but compiler is broken: disabling >&2 1133 - else 1134 - @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ 1135 - $(stackp-flag) available but compiler is broken >&2 && exit 1 1136 - endif 1137 - endif 1138 - @: 1139 1146 1140 1147 # Generate some files 1141 1148 # ---------------------------------------------------------------------------
+11 -21
arch/Kconfig
··· 536 536 bool 537 537 help 538 538 An arch should select this symbol if: 539 - - its compiler supports the -fstack-protector option 540 539 - it has implemented a stack canary (e.g. __stack_chk_guard) 541 540 542 - choice 543 - prompt "Stack Protector buffer overflow detection" 541 + config CC_HAS_STACKPROTECTOR_NONE 542 + def_bool $(cc-option,-fno-stack-protector) 543 + 544 + config CC_STACKPROTECTOR 545 + bool "Stack Protector buffer overflow detection" 544 546 depends on HAVE_CC_STACKPROTECTOR 545 - default CC_STACKPROTECTOR_AUTO 547 + depends on $(cc-option,-fstack-protector) 548 + default y 546 549 help 547 550 This option turns on the "stack-protector" GCC feature. This 548 551 feature puts, at the beginning of functions, a canary value on ··· 555 552 overwrite the canary, which gets detected and the attack is then 556 553 neutralized via a kernel panic. 557 554 558 - config CC_STACKPROTECTOR_NONE 559 - bool "None" 560 - help 561 - Disable "stack-protector" GCC feature. 562 - 563 - config CC_STACKPROTECTOR_REGULAR 564 - bool "Regular" 565 - help 566 555 Functions will have the stack-protector canary logic added if they 567 556 have an 8-byte or larger character array on the stack. 568 557 ··· 566 571 by about 0.3%. 567 572 568 573 config CC_STACKPROTECTOR_STRONG 569 - bool "Strong" 574 + bool "Strong Stack Protector" 575 + depends on CC_STACKPROTECTOR 576 + depends on $(cc-option,-fstack-protector-strong) 577 + default y 570 578 help 571 579 Functions will have the stack-protector canary logic added in any 572 580 of the following conditions: ··· 586 588 On an x86 "defconfig" build, this feature adds canary checks to 587 589 about 20% of all kernel functions, which increases the kernel code 588 590 size by about 2%. 589 - 590 - config CC_STACKPROTECTOR_AUTO 591 - bool "Automatic" 592 - help 593 - If the compiler supports it, the best available stack-protector 594 - option will be chosen. 595 - 596 - endchoice 597 591 598 592 config HAVE_ARCH_WITHIN_STACK_FRAMES 599 593 bool
+10 -1
arch/x86/Kconfig
··· 129 129 select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64 130 130 select HAVE_ARCH_VMAP_STACK if X86_64 131 131 select HAVE_ARCH_WITHIN_STACK_FRAMES 132 - select HAVE_CC_STACKPROTECTOR 132 + select HAVE_CC_STACKPROTECTOR if CC_HAS_SANE_STACKPROTECTOR 133 133 select HAVE_CMPXCHG_DOUBLE 134 134 select HAVE_CMPXCHG_LOCAL 135 135 select HAVE_CONTEXT_TRACKING if X86_64 ··· 341 341 default 2 342 342 343 343 source "init/Kconfig" 344 + 345 + config CC_HAS_SANE_STACKPROTECTOR 346 + bool 347 + default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT 348 + default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC)) 349 + help 350 + We have to make sure stack protector is unconditionally disabled if 351 + the compiler produces broken code. 352 + 344 353 source "kernel/Kconfig.freezer" 345 354 346 355 menu "Processor type and features"
+1 -6
scripts/gcc-x86_32-has-stack-protector.sh
··· 1 1 #!/bin/sh 2 2 # SPDX-License-Identifier: GPL-2.0 3 3 4 - echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" 5 - if [ "$?" -eq "0" ] ; then 6 - echo y 7 - else 8 - echo n 9 - fi 4 + echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
-5
scripts/gcc-x86_64-has-stack-protector.sh
··· 2 2 # SPDX-License-Identifier: GPL-2.0 3 3 4 4 echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs" 5 - if [ "$?" -eq "0" ] ; then 6 - echo y 7 - else 8 - echo n 9 - fi