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 --- arch/x86/Kconfig | 1 + arch/x86/entry/vdso/Makefile | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/x86') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0a7b885964ba..65e7701bd429 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -111,6 +111,7 @@ config X86 select HAVE_FUNCTION_GRAPH_FP_TEST select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER + select HAVE_GCC_PLUGINS select HAVE_GENERIC_DMA_COHERENT if X86_32 select HAVE_HW_BREAKPOINT select HAVE_IDE diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 253b72eaade6..f9123163a850 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -75,7 +75,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ -fno-omit-frame-pointer -foptimize-sibling-calls \ -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO -$(vobjs): KBUILD_CFLAGS += $(CFL) +$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) # # vDSO code runs in userspace and -pg doesn't help with profiling anyway. @@ -145,6 +145,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32)) +KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) -- 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 'arch/x86') 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 58ab5e0c2c40ec48e682179e8f2e4cda2ece201b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 17:45:46 +0200 Subject: Kbuild: arch: look for generated headers in obtree There are very few files that need add an -I$(obj) gcc for the preprocessor or the assembler. For C files, we add always these for both the objtree and srctree, but for the other ones we require the Makefile to add them, and Kbuild then adds it for both trees. As a preparation for changing the meaning of the -I$(obj) directive to only refer to the srctree, this changes the two instances in arch/x86 to use an explictit $(objtree) prefix where needed, otherwise we won't find the headers any more, as reported by the kbuild 0day builder. arch/x86/realmode/rm/realmode.lds.S:75:20: fatal error: pasyms.h: No such file or directory Signed-off-by: Arnd Bergmann Signed-off-by: Michal Marek --- arch/alpha/boot/Makefile | 2 +- arch/powerpc/boot/Makefile | 2 +- arch/powerpc/kvm/Makefile | 2 +- arch/s390/boot/compressed/Makefile | 4 ++-- arch/um/Makefile | 4 ++-- arch/x86/boot/Makefile | 2 +- arch/x86/realmode/rm/Makefile | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) (limited to 'arch/x86') diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile index 8399bd0e68e8..0cbe4c59d3ce 100644 --- a/arch/alpha/boot/Makefile +++ b/arch/alpha/boot/Makefile @@ -15,7 +15,7 @@ targets := vmlinux.gz vmlinux \ OBJSTRIP := $(obj)/tools/objstrip HOSTCFLAGS := -Wall -I$(objtree)/usr/include -BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) +BOOTCFLAGS += -I$(objtree)/$(obj) -I$(srctree)/$(obj) # SRM bootable image. Copy to offset 512 of a partition. $(obj)/bootimage: $(addprefix $(obj)/tools/,mkbb lxboot bootlx) $(obj)/vmlinux.nh diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8fe78a3efc92..ad3782610cf1 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -43,7 +43,7 @@ ifeq ($(call cc-option-yn, -fstack-protector),y) BOOTCFLAGS += -fno-stack-protector endif -BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) +BOOTCFLAGS += -I$(objtree)/$(obj) -I$(srctree)/$(obj) DTC_FLAGS ?= -p 1024 diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index eba0bea6e032..1f9e5529e692 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -20,7 +20,7 @@ common-objs-y += powerpc.o emulate.o emulate_loadstore.o obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o obj-$(CONFIG_KVM_BOOK3S_HANDLER) += book3s_exports.o -AFLAGS_booke_interrupts.o := -I$(obj) +AFLAGS_booke_interrupts.o := -I$(objtree)/$(obj) kvm-e500-objs := \ $(common-objs-y) \ diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 1dd210347e12..2657a29a2026 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -31,10 +31,10 @@ quiet_cmd_sizes = GEN $@ $(obj)/sizes.h: vmlinux $(call if_changed,sizes) -AFLAGS_head.o += -I$(obj) +AFLAGS_head.o += -I$(objtree)/$(obj) $(obj)/head.o: $(obj)/sizes.h -CFLAGS_misc.o += -I$(obj) +CFLAGS_misc.o += -I$(objtree)/$(obj) $(obj)/misc.o: $(obj)/sizes.h OBJCOPYFLAGS_vmlinux.bin := -R .comment -S diff --git a/arch/um/Makefile b/arch/um/Makefile index e3abe6f3156d..0ca46ededfc7 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -78,8 +78,8 @@ include $(ARCH_DIR)/Makefile-os-$(OS) KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \ -I$(srctree)/$(HOST_DIR)/include/uapi \ - -I$(HOST_DIR)/include/generated \ - -I$(HOST_DIR)/include/generated/uapi + -I$(objtree)/$(HOST_DIR)/include/generated \ + -I$(objtree)/$(HOST_DIR)/include/generated/uapi # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 700a9c6e6159..f3784c35fda2 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -96,7 +96,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE $(call if_changed,zoffset) -AFLAGS_header.o += -I$(obj) +AFLAGS_header.o += -I$(objtree)/$(obj) $(obj)/header.o: $(obj)/zoffset.h LDFLAGS_setup.elf := -T diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index c556c5ae8de5..25012abc3409 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -48,7 +48,7 @@ targets += realmode.lds $(obj)/realmode.lds: $(obj)/pasyms.h LDFLAGS_realmode.elf := --emit-relocs -T -CPPFLAGS_realmode.lds += -P -C -I$(obj) +CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj) targets += realmode.elf $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE -- 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 'arch/x86') 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