From 6b90bd4ba40b38dc13c2782469c1c77e4ed79915 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 24 May 2016 00:09:38 +0200 Subject: GCC plugin infrastructure This patch allows to build the whole kernel with GCC plugins. It was ported from grsecurity/PaX. The infrastructure supports building out-of-tree modules and building in a separate directory. Cross-compilation is supported too. Currently the x86, arm, arm64 and uml architectures enable plugins. The directory of the gcc plugins is scripts/gcc-plugins. You can use a file or a directory there. The plugins compile with these options: * -fno-rtti: gcc is compiled with this option so the plugins must use it too * -fno-exceptions: this is inherited from gcc too * -fasynchronous-unwind-tables: this is inherited from gcc too * -ggdb: it is useful for debugging a plugin (better backtrace on internal errors) * -Wno-narrowing: to suppress warnings from gcc headers (ipa-utils.h) * -Wno-unused-variable: to suppress warnings from gcc headers (gcc_version variable, plugin-version.h) The infrastructure introduces a new Makefile target called gcc-plugins. It supports all gcc versions from 4.5 to 6.0. The scripts/gcc-plugin.sh script chooses the proper host compiler (gcc-4.7 can be built by either gcc or g++). This script also checks the availability of the included headers in scripts/gcc-plugins/gcc-common.h. The gcc-common.h header contains frequently included headers for GCC plugins and it has a compatibility layer for the supported gcc versions. The gcc-generate-*-pass.h headers automatically generate the registration structures for GIMPLE, SIMPLE_IPA, IPA and RTL passes. Note that 'make clean' keeps the *.so files (only the distclean or mrproper targets clean all) because they are needed for out-of-tree modules. Based on work created by the PaX Team. Signed-off-by: Emese Revfy Acked-by: Kees Cook Signed-off-by: Michal Marek --- Makefile | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 0f70de63cfdb..20fcf4b26fbc 100644 --- a/Makefile +++ b/Makefile @@ -552,7 +552,7 @@ ifeq ($(KBUILD_EXTMOD),) # in parallel PHONY += scripts scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \ - asm-generic + asm-generic gcc-plugins $(Q)$(MAKE) $(build)=$(@) # Objects we will link into vmlinux / subdirs we need to visit @@ -631,6 +631,15 @@ endif # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) +PHONY += gcc-plugins +gcc-plugins: scripts_basic +ifdef CONFIG_GCC_PLUGINS + $(Q)$(MAKE) $(build)=scripts/gcc-plugins +endif + @: + +include scripts/Makefile.gcc-plugins + ifdef CONFIG_READABLE_ASM # Disable optimizations that make assembler listings hard to read. # reorder blocks reorders the control in the function @@ -1026,7 +1035,7 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \ archprepare: archheaders archscripts prepare1 scripts_basic -prepare0: archprepare +prepare0: archprepare gcc-plugins $(Q)$(MAKE) $(build)=. # All the preparing.. @@ -1507,6 +1516,7 @@ clean: $(clean-dirs) -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name modules.builtin -o -name '.tmp_*.o.*' \ + -o -name '*.c.[012]*.*' \ -o -name '*.gcno' \) -type f -print | xargs rm -f # Generate tags for editors -- cgit v1.2.3-59-g8ed1b From 543c37cb165049c3be24a0d4733e67caa2b33eef Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 24 May 2016 00:11:37 +0200 Subject: Add sancov plugin The sancov gcc plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks. This plugin is a helper plugin for the kcov feature. It supports all gcc versions with plugin support (from gcc-4.5 on). It is based on the gcc commit "Add fuzzing coverage support" by Dmitry Vyukov (https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296). Signed-off-by: Emese Revfy Acked-by: Kees Cook Signed-off-by: Michal Marek --- Makefile | 10 +-- arch/Kconfig | 9 +++ arch/x86/purgatory/Makefile | 2 + lib/Kconfig.debug | 2 + scripts/Makefile.gcc-plugins | 21 +++++- scripts/gcc-plugins/Makefile | 6 ++ scripts/gcc-plugins/sancov_plugin.c | 144 ++++++++++++++++++++++++++++++++++++ 7 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 scripts/gcc-plugins/sancov_plugin.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 20fcf4b26fbc..c3d494ba3ae1 100644 --- a/Makefile +++ b/Makefile @@ -369,7 +369,7 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im -Wno-maybe-uninitialized -CFLAGS_KCOV = -fsanitize-coverage=trace-pc +CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) # Use USERINCLUDE when you must reference the UAPI directories only. @@ -691,14 +691,6 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) -ifdef CONFIG_KCOV - ifeq ($(call cc-option, $(CFLAGS_KCOV)),) - $(warning Cannot use CONFIG_KCOV: \ - -fsanitize-coverage=trace-pc is not supported by compiler) - CFLAGS_KCOV = - endif -endif - ifeq ($(cc-name),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) diff --git a/arch/Kconfig b/arch/Kconfig index 04ca45262ad1..05f1e95b796d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -384,6 +384,15 @@ config GCC_PLUGIN_CYC_COMPLEXITY N = the number of nodes P = the number of connected components (exit nodes). +config GCC_PLUGIN_SANCOV + bool + depends on GCC_PLUGINS + help + This plugin inserts a __sanitizer_cov_trace_pc() call at the start of + basic blocks. It supports all gcc versions with plugin support (from + gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" + by Dmitry Vyukov . + config HAVE_CC_STACKPROTECTOR bool help diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index 12734a96df47..ac58c1616408 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -8,6 +8,8 @@ PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib targets += purgatory.ro +KCOV_INSTRUMENT := n + # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That # in turn leaves some undefined symbols like __fentry__ in purgatory and not # sure how to relocate those. Like kexec-tools, use custom flags. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 77d7d034bac3..b7827dca3fec 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -708,6 +708,8 @@ config KCOV bool "Code coverage for fuzzing" depends on ARCH_HAS_KCOV select DEBUG_FS + select GCC_PLUGINS + select GCC_PLUGIN_SANCOV help KCOV exposes kernel code coverage information in a form suitable for coverage-guided fuzzing (randomized testing). diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index b4a189c95a8a..5e22b60589c1 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -2,10 +2,26 @@ ifdef CONFIG_GCC_PLUGINS __PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC)) PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") + SANCOV_PLUGIN := -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so + gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so + + ifdef CONFIG_GCC_PLUGIN_SANCOV + ifeq ($(CFLAGS_KCOV),) + # It is needed because of the gcc-plugin.sh and gcc version checks. + gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so + + ifneq ($(PLUGINCC),) + CFLAGS_KCOV := $(SANCOV_PLUGIN) + else + $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) + endif + endif + endif + GCC_PLUGINS_CFLAGS := $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) - export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN + export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN SANCOV_PLUGIN ifeq ($(PLUGINCC),) ifneq ($(GCC_PLUGINS_CFLAGS),) @@ -16,6 +32,9 @@ ifdef CONFIG_GCC_PLUGINS $(warning warning: your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least) endif endif + else + # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. + GCC_PLUGINS_CFLAGS := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGINS_CFLAGS)) endif KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index c60ba4bef57c..88c8ec47232b 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -14,8 +14,14 @@ endif export GCCPLUGINS_DIR HOSTLIBS +ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN)) + GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN)) +endif + $(HOSTLIBS)-y := $(GCC_PLUGIN) always := $($(HOSTLIBS)-y) cyc_complexity_plugin-objs := cyc_complexity_plugin.o +sancov_plugin-objs := sancov_plugin.o + clean-files += *.so diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c new file mode 100644 index 000000000000..aedd6113cb73 --- /dev/null +++ b/scripts/gcc-plugins/sancov_plugin.c @@ -0,0 +1,144 @@ +/* + * Copyright 2011-2016 by Emese Revfy + * Licensed under the GPL v2, or (at your option) v3 + * + * Homepage: + * https://github.com/ephox-gcc-plugins/sancov + * + * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks. + * It supports all gcc versions with plugin support (from gcc-4.5 on). + * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov . + * + * You can read about it more here: + * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296 + * http://lwn.net/Articles/674854/ + * https://github.com/google/syzkaller + * https://lwn.net/Articles/677764/ + * + * Usage: + * make run + */ + +#include "gcc-common.h" + +int plugin_is_GPL_compatible; + +tree sancov_fndecl; + +static struct plugin_info sancov_plugin_info = { + .version = "20160402", + .help = "sancov plugin\n", +}; + +static unsigned int sancov_execute(void) +{ + basic_block bb; + + /* Remove this line when this plugin and kcov will be in the kernel. + if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl))) + return 0; + */ + + FOR_EACH_BB_FN(bb, cfun) { + const_gimple stmt; + gcall *gcall; + gimple_stmt_iterator gsi = gsi_after_labels(bb); + + if (gsi_end_p(gsi)) + continue; + + stmt = gsi_stmt(gsi); + gcall = as_a_gcall(gimple_build_call(sancov_fndecl, 0)); + gimple_set_location(gcall, gimple_location(stmt)); + gsi_insert_before(&gsi, gcall, GSI_SAME_STMT); + } + return 0; +} + +#define PASS_NAME sancov + +#define NO_GATE +#define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_stmts | TODO_update_ssa_no_phi | TODO_verify_flow + +#include "gcc-generate-gimple-pass.h" + +static void sancov_start_unit(void __unused *gcc_data, void __unused *user_data) +{ + tree leaf_attr, nothrow_attr; + tree BT_FN_VOID = build_function_type_list(void_type_node, NULL_TREE); + + sancov_fndecl = build_fn_decl("__sanitizer_cov_trace_pc", BT_FN_VOID); + + DECL_ASSEMBLER_NAME(sancov_fndecl); + TREE_PUBLIC(sancov_fndecl) = 1; + DECL_EXTERNAL(sancov_fndecl) = 1; + DECL_ARTIFICIAL(sancov_fndecl) = 1; + DECL_PRESERVE_P(sancov_fndecl) = 1; + DECL_UNINLINABLE(sancov_fndecl) = 1; + TREE_USED(sancov_fndecl) = 1; + + nothrow_attr = tree_cons(get_identifier("nothrow"), NULL, NULL); + decl_attributes(&sancov_fndecl, nothrow_attr, 0); + gcc_assert(TREE_NOTHROW(sancov_fndecl)); +#if BUILDING_GCC_VERSION > 4005 + leaf_attr = tree_cons(get_identifier("leaf"), NULL, NULL); + decl_attributes(&sancov_fndecl, leaf_attr, 0); +#endif +} + +int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) +{ + int i; + struct register_pass_info sancov_plugin_pass_info; + const char * const plugin_name = plugin_info->base_name; + const int argc = plugin_info->argc; + const struct plugin_argument * const argv = plugin_info->argv; + bool enable = true; + + static const struct ggc_root_tab gt_ggc_r_gt_sancov[] = { + { + .base = &sancov_fndecl, + .nelt = 1, + .stride = sizeof(sancov_fndecl), + .cb = >_ggc_mx_tree_node, + .pchw = >_pch_nx_tree_node + }, + LAST_GGC_ROOT_TAB + }; + + /* BBs can be split afterwards?? */ + sancov_plugin_pass_info.pass = make_sancov_pass(); +#if BUILDING_GCC_VERSION >= 4009 + sancov_plugin_pass_info.reference_pass_name = "asan"; +#else + sancov_plugin_pass_info.reference_pass_name = "nrv"; +#endif + sancov_plugin_pass_info.ref_pass_instance_number = 0; + sancov_plugin_pass_info.pos_op = PASS_POS_INSERT_BEFORE; + + if (!plugin_default_version_check(version, &gcc_version)) { + error(G_("incompatible gcc/plugin versions")); + return 1; + } + + for (i = 0; i < argc; ++i) { + if (!strcmp(argv[i].key, "no-sancov")) { + enable = false; + continue; + } + error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + } + + register_callback(plugin_name, PLUGIN_INFO, NULL, &sancov_plugin_info); + + if (!enable) + return 0; + +#if BUILDING_GCC_VERSION < 6000 + register_callback(plugin_name, PLUGIN_START_UNIT, &sancov_start_unit, NULL); + register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_sancov); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_plugin_pass_info); +#endif + + return 0; +} -- cgit v1.2.3-59-g8ed1b From dc33db7c338e1a7a4a7cb94d73745c8ca54b1ac8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 17:45:44 +0200 Subject: Kbuild: avoid duplicate include path arch/$(hdr-arch)/include/generated/uapi is included twice in the header search path, which is unnecessary, so this changes the top-level Makefile to drop the second instance by filtering out everything from USERINCLUDE that was already part of LINUXINCLUDE. This should have very little effect other than making the 'make V=1' output slightly smaller and making the build time faster by a miniscule amount, but it seems to be cleaner. Signed-off-by: Arnd Bergmann Signed-off-by: Michal Marek --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index c3d494ba3ae1..337686db5fd3 100644 --- a/Makefile +++ b/Makefile @@ -387,8 +387,9 @@ LINUXINCLUDE := \ -Iarch/$(hdr-arch)/include/generated/uapi \ -Iarch/$(hdr-arch)/include/generated \ $(if $(KBUILD_SRC), -I$(srctree)/include) \ - -Iinclude \ - $(USERINCLUDE) + -Iinclude + +LINUXINCLUDE += $(filter-out $(LINUXINCLUDE),$(USERINCLUDE)) KBUILD_CPPFLAGS := -D__KERNEL__ -- cgit v1.2.3-59-g8ed1b From 3308b28569ba3327419658edd194a967e3fd51e2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 17:45:45 +0200 Subject: Kbuild: always prefix objtree in LINUXINCLUDE When $(LINUXINCLUDE) is added to the cflags of a target that normall doesn't have it (e.g. HOSTCFLAGS), each entry in the list is expanded so that we search both $(objtree) and $(srctree), which is a bit silly, as we already know which of the two we want for each entry in LINUXINCLUDE. Also, a follow-up patch changes the behavior so we only look in $(srctree) for manually added include path, and that breaks finding the generated headers. This adds an explicit $(objtree) for each tree that we want to look for generated files. Signed-off-by: Arnd Bergmann Signed-off-by: Michal Marek --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 337686db5fd3..64684b19d49c 100644 --- a/Makefile +++ b/Makefile @@ -375,19 +375,19 @@ CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ -I$(srctree)/arch/$(hdr-arch)/include/uapi \ - -Iarch/$(hdr-arch)/include/generated/uapi \ + -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \ -I$(srctree)/include/uapi \ - -Iinclude/generated/uapi \ + -I$(objtree)/include/generated/uapi \ -include $(srctree)/include/linux/kconfig.h # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE := \ -I$(srctree)/arch/$(hdr-arch)/include \ - -Iarch/$(hdr-arch)/include/generated/uapi \ - -Iarch/$(hdr-arch)/include/generated \ + -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \ + -I$(objtree)/arch/$(hdr-arch)/include/generated \ $(if $(KBUILD_SRC), -I$(srctree)/include) \ - -Iinclude + -I$(objtree)/include LINUXINCLUDE += $(filter-out $(LINUXINCLUDE),$(USERINCLUDE)) -- cgit v1.2.3-59-g8ed1b From ddea05fa148b4d8e66498e522a616d87f9cf81e3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Jul 2016 16:39:35 +0200 Subject: kbuild: make samples depend on headers_install Olof's build test setup keeps failing to compile arm64 kernels because of a toolchain that uses outdated kernel headers: /work/build/batch/samples/seccomp/bpf-fancy.c:13:27: fatal error: linux/seccomp.h: No such file or directory This is of course something he could change, but it also indicates that others may run into the same problem. Running 'make headers_install' avoids the issue by ensuring that the kernel headers are put into the $(objdir)/usr/include path before we build the samples. The same problem happened for the Documentation build in the past and was fixed up with commit 8e2faea877eb ("Make Documenation depend on headers_install"). This adds an identical Makefile dependency for the samples/ subdirectory. Signed-off-by: Arnd Bergmann Signed-off-by: Michal Marek --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 64684b19d49c..7aa6f8c4cc53 100644 --- a/Makefile +++ b/Makefile @@ -1620,7 +1620,7 @@ endif $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ $(build)=$(build-dir) # Make sure the latest headers are built for Documentation -Documentation/: headers_install +Documentation/ samples/: headers_install %/: prepare scripts FORCE $(cmd_crmodverdir) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ -- cgit v1.2.3-59-g8ed1b From 228d96c603cf53e32f672c0e459d2adbc5a4609a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 26 Jul 2016 14:26:20 -0700 Subject: kbuild: Abort build on bad stack protector flag Before, the stack protector flag was sanity checked before .config had been reprocessed. This meant the build couldn't be aborted early, and only a warning could be emitted followed later by the compiler blowing up with an unknown flag. This has caused a lot of confusion over time, so this splits the flag selection from sanity checking and performs the sanity checking after the make has been restarted from a reprocessed .config, so builds can be aborted as early as possible now. Additionally moves the x86-specific sanity check to the same location, since it suffered from the same warn-then-wait-for-compiler-failure problem. Signed-off-by: Kees Cook Signed-off-by: Michal Marek --- Makefile | 67 +++++++++++++++++++++++++++++++++---------------------- arch/x86/Makefile | 8 ------- 2 files changed, 40 insertions(+), 35 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 7aa6f8c4cc53..08aac0a7c85f 100644 --- a/Makefile +++ b/Makefile @@ -655,41 +655,26 @@ ifneq ($(CONFIG_FRAME_WARN),0) KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN}) endif -# Handle stack protector mode. -# -# Since kbuild can potentially perform two passes (first with the old -# .config values and then with updated .config values), we cannot error out -# if a desired compiler option is unsupported. If we were to error, kbuild -# could never get to the second pass and actually notice that we changed -# the option to something that was supported. -# -# Additionally, 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. ("But I -# selected CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!") -# -# The middle ground is to warn here so that the failed option is obvious, but -# to let the build fail with bad compiler flags so that we can't produce a -# kernel when there is a CONFIG and compiler mismatch. -# +# 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_REGULAR stackp-flag := -fstack-protector - ifeq ($(call cc-option, $(stackp-flag)),) - $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \ - -fstack-protector not supported by compiler) - endif + stackp-name := REGULAR else ifdef CONFIG_CC_STACKPROTECTOR_STRONG stackp-flag := -fstack-protector-strong - ifeq ($(call cc-option, $(stackp-flag)),) - $(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \ - -fstack-protector-strong not supported by compiler) - endif + stackp-name := STRONG else # Force off for distro compilers that enable stack protector by default. stackp-flag := $(call cc-option, -fno-stack-protector) endif endif +# Find arch-specific stack protector compiler sanity-checking script. +ifdef CONFIG_CC_STACKPROTECTOR + stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh + stackp-check := $(wildcard $(stackp-path)) +endif KBUILD_CFLAGS += $(stackp-flag) ifeq ($(cc-name),clang) @@ -1017,8 +1002,10 @@ ifneq ($(KBUILD_SRC),) fi; endif -# prepare2 creates a makefile if using a separate output directory -prepare2: prepare3 outputmakefile asm-generic +# 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 prepare1: prepare2 $(version_h) include/generated/utsrelease.h \ include/config/auto.conf @@ -1049,6 +1036,32 @@ endif 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 + 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 +# Make sure compiler does not have buggy stack-protector support. +ifdef stackp-check + ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) + @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ + $(stackp-flag) available but compiler is broken >&2 && exit 1 + endif +endif + @: + # Generate some files # --------------------------------------------------------------------------- diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 6fce7f096b88..830ed391e7ef 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -126,14 +126,6 @@ else KBUILD_CFLAGS += $(call cc-option,-maccumulate-outgoing-args) endif -# Make sure compiler does not have buggy stack-protector support. -ifdef CONFIG_CC_STACKPROTECTOR - cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh - ifneq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) - $(warning stack-protector enabled but compiler support broken) - endif -endif - ifdef CONFIG_X86_X32 x32_ld_ok := $(call try-run,\ /bin/echo -e '1: .quad 1b' | \ -- cgit v1.2.3-59-g8ed1b