stack-protector: test compiler capability in Kconfig and drop AUTO mode
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Mon, 28 May 2018 09:22:00 +0000 (18:22 +0900)
committerMasahiro Yamada <yamada.masahiro@socionext.com>
Fri, 8 Jun 2018 09:56:00 +0000 (18:56 +0900)
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>
Makefile
arch/Kconfig
arch/x86/Kconfig
scripts/gcc-x86_32-has-stack-protector.sh
scripts/gcc-x86_64-has-stack-protector.sh

index 747edaf11559a42991592d1b1035a24e358537c3..ca9d98b4a71b4ecab23e03da4a3bac7f28fb070c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -686,55 +686,11 @@ ifneq ($(CONFIG_FRAME_WARN),0)
 KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
 endif
 
-# This selects the stack protector compiler flag. Testing it is delayed
-# until after .config has been reprocessed, in the prepare-compiler-check
-# target.
-ifdef CONFIG_CC_STACKPROTECTOR_AUTO
-  stackp-flag := $(call cc-option,-fstack-protector-strong,$(call cc-option,-fstack-protector))
-  stackp-name := AUTO
-else
-ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
-  stackp-flag := -fstack-protector
-  stackp-name := REGULAR
-else
-ifdef CONFIG_CC_STACKPROTECTOR_STRONG
-  stackp-flag := -fstack-protector-strong
-  stackp-name := STRONG
-else
-  # If either there is no stack protector for this architecture or
-  # CONFIG_CC_STACKPROTECTOR_NONE is selected, we're done, and $(stackp-name)
-  # is empty, skipping all remaining stack protector tests.
-  #
-  # Force off for distro compilers that enable stack protector by default.
-  KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
-endif
-endif
-endif
-# Find arch-specific stack protector compiler sanity-checking script.
-ifdef stackp-name
-ifneq ($(stackp-flag),)
-  stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh
-  stackp-check := $(wildcard $(stackp-path))
-  # If the wildcard test matches a test script, run it to check functionality.
-  ifdef stackp-check
-    ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y)
-      stackp-broken := y
-    endif
-  endif
-  ifndef stackp-broken
-    # If the stack protector is functional, enable code that depends on it.
-    KBUILD_CPPFLAGS += -DCONFIG_CC_STACKPROTECTOR
-    # Either we've already detected the flag (for AUTO) or we'll fail the
-    # build in the prepare-compiler-check rule (for specific flag).
-    KBUILD_CFLAGS += $(stackp-flag)
-  else
-    # We have to make sure stack protector is unconditionally disabled if
-    # the compiler is broken (in case we're going to continue the build in
-    # AUTO mode).
-    KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
-  endif
-endif
-endif
+stackp-flags-$(CONFIG_CC_HAS_STACKPROTECTOR_NONE) := -fno-stack-protector
+stackp-flags-$(CONFIG_CC_STACKPROTECTOR)          := -fstack-protector
+stackp-flags-$(CONFIG_CC_STACKPROTECTOR_STRONG)   := -fstack-protector-strong
+
+KBUILD_CFLAGS += $(stackp-flags-y)
 
 ifeq ($(cc-name),clang)
 KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
@@ -1118,7 +1074,7 @@ endif
 # prepare2 creates a makefile if using a separate output directory.
 # From this point forward, .config has been reprocessed, so any rules
 # that need to depend on updated CONFIG_* values can be checked here.
-prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic
+prepare2: prepare3 outputmakefile asm-generic
 
 prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h \
                    include/config/auto.conf
@@ -1144,43 +1100,6 @@ uapi-asm-generic:
 PHONY += prepare-objtool
 prepare-objtool: $(objtool_target)
 
-# Check for CONFIG flags that require compiler support. Abort the build
-# after .config has been processed, but before the kernel build starts.
-#
-# For security-sensitive CONFIG options, we don't want to fallback and/or
-# silently change which compiler flags will be used, since that leads to
-# producing kernels with different security feature characteristics
-# depending on the compiler used. (For example, "But I selected
-# CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!")
-PHONY += prepare-compiler-check
-prepare-compiler-check: FORCE
-# Make sure compiler supports requested stack protector flag.
-ifdef stackp-name
-  # Warn about CONFIG_CC_STACKPROTECTOR_AUTO having found no option.
-  ifeq ($(stackp-flag),)
-       @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \
-                 Compiler does not support any known stack-protector >&2
-  else
-  # Fail if specifically requested stack protector is missing.
-  ifeq ($(call cc-option, $(stackp-flag)),)
-       @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \
-                 $(stackp-flag) not supported by compiler >&2 && exit 1
-  endif
-  endif
-endif
-# Make sure compiler does not have buggy stack-protector support. If a
-# specific stack-protector was requested, fail the build, otherwise warn.
-ifdef stackp-broken
-  ifeq ($(stackp-name),AUTO)
-       @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \
-                  $(stackp-flag) available but compiler is broken: disabling >&2
-  else
-       @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \
-                  $(stackp-flag) available but compiler is broken >&2 && exit 1
-  endif
-endif
-       @:
-
 # Generate some files
 # ---------------------------------------------------------------------------
 
index 8a7f7e1f2ca745dee2cac1d188a5389a46de406d..2c7c3cf8adfc279f6d2f375a155409593e6fefec 100644 (file)
@@ -536,13 +536,16 @@ config HAVE_CC_STACKPROTECTOR
        bool
        help
          An arch should select this symbol if:
-         - its compiler supports the -fstack-protector option
          - it has implemented a stack canary (e.g. __stack_chk_guard)
 
-choice
-       prompt "Stack Protector buffer overflow detection"
+config CC_HAS_STACKPROTECTOR_NONE
+       def_bool $(cc-option,-fno-stack-protector)
+
+config CC_STACKPROTECTOR
+       bool "Stack Protector buffer overflow detection"
        depends on HAVE_CC_STACKPROTECTOR
-       default CC_STACKPROTECTOR_AUTO
+       depends on $(cc-option,-fstack-protector)
+       default y
        help
          This option turns on the "stack-protector" GCC feature. This
          feature puts, at the beginning of functions, a canary value on
@@ -552,14 +555,6 @@ choice
          overwrite the canary, which gets detected and the attack is then
          neutralized via a kernel panic.
 
-config CC_STACKPROTECTOR_NONE
-       bool "None"
-       help
-         Disable "stack-protector" GCC feature.
-
-config CC_STACKPROTECTOR_REGULAR
-       bool "Regular"
-       help
          Functions will have the stack-protector canary logic added if they
          have an 8-byte or larger character array on the stack.
 
@@ -571,7 +566,10 @@ config CC_STACKPROTECTOR_REGULAR
          by about 0.3%.
 
 config CC_STACKPROTECTOR_STRONG
-       bool "Strong"
+       bool "Strong Stack Protector"
+       depends on CC_STACKPROTECTOR
+       depends on $(cc-option,-fstack-protector-strong)
+       default y
        help
          Functions will have the stack-protector canary logic added in any
          of the following conditions:
@@ -589,14 +587,6 @@ config CC_STACKPROTECTOR_STRONG
          about 20% of all kernel functions, which increases the kernel code
          size by about 2%.
 
-config CC_STACKPROTECTOR_AUTO
-       bool "Automatic"
-       help
-         If the compiler supports it, the best available stack-protector
-         option will be chosen.
-
-endchoice
-
 config HAVE_ARCH_WITHIN_STACK_FRAMES
        bool
        help
index cb6e3a21929473ca003b8227a6f97fc4b8335f79..50a1b8ec9ad9ebf0a147b8d7e44c038399f454ba 100644 (file)
@@ -129,7 +129,7 @@ config X86
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64
        select HAVE_ARCH_VMAP_STACK             if X86_64
        select HAVE_ARCH_WITHIN_STACK_FRAMES
-       select HAVE_CC_STACKPROTECTOR
+       select HAVE_CC_STACKPROTECTOR           if CC_HAS_SANE_STACKPROTECTOR
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
        select HAVE_CONTEXT_TRACKING            if X86_64
@@ -341,6 +341,15 @@ config PGTABLE_LEVELS
        default 2
 
 source "init/Kconfig"
+
+config CC_HAS_SANE_STACKPROTECTOR
+       bool
+       default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT
+       default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC))
+       help
+          We have to make sure stack protector is unconditionally disabled if
+          the compiler produces broken code.
+
 source "kernel/Kconfig.freezer"
 
 menu "Processor type and features"
index 6b2aeefb9cd3e0884da9ce0cfaaa8d288e03a6ee..f5c11949525404f43a22e6efb14a59207898ff9d 100755 (executable)
@@ -1,9 +1,4 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
-if [ "$?" -eq "0" ] ; then
-       echo y
-else
-       echo n
-fi
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
index 4a48bdcd4d6be6309eb895f197d370bb7b6c60db..3755af0cd9f7f24c1942fd9df216c525f79d04b3 100755 (executable)
@@ -2,8 +2,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
 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"
-if [ "$?" -eq "0" ] ; then
-       echo y
-else
-       echo n
-fi