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

kcov: test compiler capability in Kconfig and correct dependency

As Documentation/kbuild/kconfig-language.txt notes, 'select' should be
be used with care - it forces a lower limit of another symbol, ignoring
the dependency. Currently, KCOV can select GCC_PLUGINS even if arch
does not select HAVE_GCC_PLUGINS. This could cause the unmet direct
dependency.

Now that Kconfig can test compiler capability, let's handle this in a
more sophisticated way.

There are two ways to enable KCOV; use the compiler that natively
supports -fsanitize-coverage=trace-pc, or build the SANCOV plugin if
the compiler has ability to build GCC plugins. Hence, the correct
dependency for KCOV is:

depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS

You do not need to build the SANCOV plugin if the compiler already
supports -fsanitize-coverage=trace-pc. Hence, the select should be:

select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC

With this, GCC_PLUGIN_SANCOV is selected only when necessary, so
scripts/Makefile.gcc-plugins can be cleaner.

I also cleaned up Kconfig and scripts/Makefile.kcov as well.

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

+16 -19
+1 -1
Makefile
··· 601 601 CFLAGS_GCOV := -fprofile-arcs -ftest-coverage \ 602 602 $(call cc-option,-fno-tree-loop-im) \ 603 603 $(call cc-disable-warning,maybe-uninitialized,) 604 - export CFLAGS_GCOV CFLAGS_KCOV 604 + export CFLAGS_GCOV 605 605 606 606 # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default 607 607 # values of the respective KBUILD_* variables
+7 -4
lib/Kconfig.debug
··· 736 736 only for x86_64. KCOV requires testing on other archs, and most likely 737 737 disabling of instrumentation for some early boot code. 738 738 739 + config CC_HAS_SANCOV_TRACE_PC 740 + def_bool $(cc-option,-fsanitize-coverage=trace-pc) 741 + 739 742 config KCOV 740 743 bool "Code coverage for fuzzing" 741 744 depends on ARCH_HAS_KCOV 745 + depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS 742 746 select DEBUG_FS 743 - select GCC_PLUGINS if !COMPILE_TEST 744 - select GCC_PLUGIN_SANCOV if !COMPILE_TEST 747 + select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC 745 748 help 746 749 KCOV exposes kernel code coverage information in a form suitable 747 750 for coverage-guided fuzzing (randomized testing). ··· 758 755 config KCOV_ENABLE_COMPARISONS 759 756 bool "Enable comparison operands collection by KCOV" 760 757 depends on KCOV 761 - default n 758 + depends on $(cc-option,-fsanitize-coverage=trace-cmp) 762 759 help 763 760 KCOV also exposes operands of every comparison in the instrumented 764 761 code along with operand sizes and PCs of the comparison instructions. ··· 768 765 config KCOV_INSTRUMENT_ALL 769 766 bool "Instrument all code by default" 770 767 depends on KCOV 771 - default y if KCOV 768 + default y 772 769 help 773 770 If you are doing generic system call fuzzing (like e.g. syzkaller), 774 771 then you will want to instrument the whole kernel and you should
+2 -6
scripts/Makefile.gcc-plugins
··· 14 14 endif 15 15 16 16 ifdef CONFIG_GCC_PLUGIN_SANCOV 17 - ifeq ($(strip $(CFLAGS_KCOV)),) 18 17 # It is needed because of the gcc-plugin.sh and gcc version checks. 19 18 gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so 20 19 21 - ifneq ($(PLUGINCC),) 22 - CFLAGS_KCOV := $(SANCOV_PLUGIN) 23 - else 20 + ifeq ($(PLUGINCC),) 24 21 $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) 25 22 endif 26 - endif 27 23 endif 28 24 29 25 gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so ··· 34 38 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) 35 39 36 40 export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR 37 - export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN 41 + export DISABLE_LATENT_ENTROPY_PLUGIN 38 42 39 43 ifneq ($(PLUGINCC),) 40 44 # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication.
+6 -4
scripts/Makefile.kcov
··· 1 1 ifdef CONFIG_KCOV 2 - CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) 3 - ifeq ($(CONFIG_KCOV_ENABLE_COMPARISONS),y) 4 - CFLAGS_KCOV += $(call cc-option,-fsanitize-coverage=trace-cmp,) 5 - endif 2 + 3 + kcov-flags-$(CONFIG_CC_HAS_SANCOV_TRACE_PC) += -fsanitize-coverage=trace-pc 4 + kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp 5 + kcov-flags-$(CONFIG_GCC_PLUGIN_SANCOV) += -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so 6 + 7 + export CFLAGS_KCOV := $(kcov-flags-y) 6 8 7 9 endif
-4
scripts/gcc-plugins/Makefile
··· 13 13 export HOST_EXTRACXXFLAGS 14 14 endif 15 15 16 - ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN)) 17 - GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN)) 18 - endif 19 - 20 16 export HOSTLIBS 21 17 22 18 $(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h