aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-03-22 17:27:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commit5c9a8750a6409c63a0f01d51a9024861022f6593 (patch)
tree61c5cd39711d26f755a30a7f0fd52f91c1f56387
parentade356b99a4187578609f2a91c4d2ed88e4e70dc (diff)
kernel: add kcov code coverage
kcov provides code coverage collection for coverage-guided fuzzing (randomized testing). Coverage-guided fuzzing is a testing technique that uses coverage feedback to determine new interesting inputs to a system. A notable user-space example is AFL (http://lcamtuf.coredump.cx/afl/). However, this technique is not widely used for kernel testing due to missing compiler and kernel support. kcov does not aim to collect as much coverage as possible. It aims to collect more or less stable coverage that is function of syscall inputs. To achieve this goal it does not collect coverage in soft/hard interrupts and instrumentation of some inherently non-deterministic or non-interesting parts of kernel is disbled (e.g. scheduler, locking). Currently there is a single coverage collection mode (tracing), but the API anticipates additional collection modes. Initially I also implemented a second mode which exposes coverage in a fixed-size hash table of counters (what Quentin used in his original patch). I've dropped the second mode for simplicity. This patch adds the necessary support on kernel side. The complimentary compiler support was added in gcc revision 231296. We've used this support to build syzkaller system call fuzzer, which has found 90 kernel bugs in just 2 months: https://github.com/google/syzkaller/wiki/Found-Bugs We've also found 30+ bugs in our internal systems with syzkaller. Another (yet unexplored) direction where kcov coverage would greatly help is more traditional "blob mutation". For example, mounting a random blob as a filesystem, or receiving a random blob over wire. Why not gcov. Typical fuzzing loop looks as follows: (1) reset coverage, (2) execute a bit of code, (3) collect coverage, repeat. A typical coverage can be just a dozen of basic blocks (e.g. an invalid input). In such context gcov becomes prohibitively expensive as reset/collect coverage steps depend on total number of basic blocks/edges in program (in case of kernel it is about 2M). Cost of kcov depends only on number of executed basic blocks/edges. On top of that, kernel requires per-thread coverage because there are always background threads and unrelated processes that also produce coverage. With inlined gcov instrumentation per-thread coverage is not possible. kcov exposes kernel PCs and control flow to user-space which is insecure. But debugfs should not be mapped as user accessible. Based on a patch by Quentin Casasnovas. [akpm@linux-foundation.org: make task_struct.kcov_mode have type `enum kcov_mode'] [akpm@linux-foundation.org: unbreak allmodconfig] [akpm@linux-foundation.org: follow x86 Makefile layout standards] Signed-off-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Kees Cook <keescook@chromium.org> Cc: syzkaller <syzkaller@googlegroups.com> Cc: Vegard Nossum <vegard.nossum@oracle.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Tavis Ormandy <taviso@google.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com> Cc: Kostya Serebryany <kcc@google.com> Cc: Eric Dumazet <edumazet@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Kees Cook <keescook@google.com> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: David Drysdale <drysdale@google.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Kirill A. Shutemov <kirill@shutemov.name> Cc: Jiri Slaby <jslaby@suse.cz> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/kcov.txt111
-rw-r--r--Makefile11
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/boot/Makefile7
-rw-r--r--arch/x86/boot/compressed/Makefile3
-rw-r--r--arch/x86/entry/vdso/Makefile3
-rw-r--r--arch/x86/kernel/Makefile6
-rw-r--r--arch/x86/kernel/apic/Makefile4
-rw-r--r--arch/x86/kernel/cpu/Makefile4
-rw-r--r--arch/x86/lib/Makefile3
-rw-r--r--arch/x86/mm/Makefile3
-rw-r--r--arch/x86/realmode/rm/Makefile3
-rw-r--r--drivers/firmware/efi/libstub/Makefile3
-rw-r--r--include/linux/kcov.h29
-rw-r--r--include/linux/sched.h11
-rw-r--r--include/uapi/linux/kcov.h10
-rw-r--r--kernel/Makefile12
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c3
-rw-r--r--kernel/kcov.c273
-rw-r--r--kernel/locking/Makefile3
-rw-r--r--kernel/rcu/Makefile4
-rw-r--r--kernel/sched/Makefile4
-rw-r--r--lib/Kconfig.debug21
-rw-r--r--lib/Makefile12
-rw-r--r--mm/Makefile15
-rw-r--r--mm/kasan/Makefile1
-rw-r--r--scripts/Makefile.lib6
28 files changed, 567 insertions, 1 deletions
diff --git a/Documentation/kcov.txt b/Documentation/kcov.txt
new file mode 100644
index 000000000000..779ff4ab1c1d
--- /dev/null
+++ b/Documentation/kcov.txt
@@ -0,0 +1,111 @@
1kcov: code coverage for fuzzing
2===============================
3
4kcov exposes kernel code coverage information in a form suitable for coverage-
5guided fuzzing (randomized testing). Coverage data of a running kernel is
6exported via the "kcov" debugfs file. Coverage collection is enabled on a task
7basis, and thus it can capture precise coverage of a single system call.
8
9Note that kcov does not aim to collect as much coverage as possible. It aims
10to collect more or less stable coverage that is function of syscall inputs.
11To achieve this goal it does not collect coverage in soft/hard interrupts
12and instrumentation of some inherently non-deterministic parts of kernel is
13disbled (e.g. scheduler, locking).
14
15Usage:
16======
17
18Configure kernel with:
19
20 CONFIG_KCOV=y
21
22CONFIG_KCOV requires gcc built on revision 231296 or later.
23Profiling data will only become accessible once debugfs has been mounted:
24
25 mount -t debugfs none /sys/kernel/debug
26
27The following program demonstrates kcov usage from within a test program:
28
29#include <stdio.h>
30#include <stddef.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/ioctl.h>
36#include <sys/mman.h>
37#include <unistd.h>
38#include <fcntl.h>
39
40#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
41#define KCOV_ENABLE _IO('c', 100)
42#define KCOV_DISABLE _IO('c', 101)
43#define COVER_SIZE (64<<10)
44
45int main(int argc, char **argv)
46{
47 int fd;
48 unsigned long *cover, n, i;
49
50 /* A single fd descriptor allows coverage collection on a single
51 * thread.
52 */
53 fd = open("/sys/kernel/debug/kcov", O_RDWR);
54 if (fd == -1)
55 perror("open"), exit(1);
56 /* Setup trace mode and trace size. */
57 if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
58 perror("ioctl"), exit(1);
59 /* Mmap buffer shared between kernel- and user-space. */
60 cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
61 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
62 if ((void*)cover == MAP_FAILED)
63 perror("mmap"), exit(1);
64 /* Enable coverage collection on the current thread. */
65 if (ioctl(fd, KCOV_ENABLE, 0))
66 perror("ioctl"), exit(1);
67 /* Reset coverage from the tail of the ioctl() call. */
68 __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
69 /* That's the target syscal call. */
70 read(-1, NULL, 0);
71 /* Read number of PCs collected. */
72 n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
73 for (i = 0; i < n; i++)
74 printf("0x%lx\n", cover[i + 1]);
75 /* Disable coverage collection for the current thread. After this call
76 * coverage can be enabled for a different thread.
77 */
78 if (ioctl(fd, KCOV_DISABLE, 0))
79 perror("ioctl"), exit(1);
80 /* Free resources. */
81 if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
82 perror("munmap"), exit(1);
83 if (close(fd))
84 perror("close"), exit(1);
85 return 0;
86}
87
88After piping through addr2line output of the program looks as follows:
89
90SyS_read
91fs/read_write.c:562
92__fdget_pos
93fs/file.c:774
94__fget_light
95fs/file.c:746
96__fget_light
97fs/file.c:750
98__fget_light
99fs/file.c:760
100__fdget_pos
101fs/file.c:784
102SyS_read
103fs/read_write.c:562
104
105If a program needs to collect coverage from several threads (independently),
106it needs to open /sys/kernel/debug/kcov in each thread separately.
107
108The interface is fine-grained to allow efficient forking of test processes.
109That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode,
110mmaps coverage buffer and then forks child processes in a loop. Child processes
111only need to enable coverage (disable happens automatically on thread end).
diff --git a/Makefile b/Makefile
index e055b969c325..b98a4f70d1b5 100644
--- a/Makefile
+++ b/Makefile
@@ -365,6 +365,7 @@ LDFLAGS_MODULE =
365CFLAGS_KERNEL = 365CFLAGS_KERNEL =
366AFLAGS_KERNEL = 366AFLAGS_KERNEL =
367CFLAGS_GCOV = -fprofile-arcs -ftest-coverage 367CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
368CFLAGS_KCOV = -fsanitize-coverage=trace-pc
368 369
369 370
370# Use USERINCLUDE when you must reference the UAPI directories only. 371# Use USERINCLUDE when you must reference the UAPI directories only.
@@ -411,7 +412,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
411export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS 412export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
412 413
413export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS 414export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
414export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN CFLAGS_UBSAN 415export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN
415export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE 416export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
416export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE 417export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
417export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL 418export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -673,6 +674,14 @@ endif
673endif 674endif
674KBUILD_CFLAGS += $(stackp-flag) 675KBUILD_CFLAGS += $(stackp-flag)
675 676
677ifdef CONFIG_KCOV
678 ifeq ($(call cc-option, $(CFLAGS_KCOV)),)
679 $(warning Cannot use CONFIG_KCOV: \
680 -fsanitize-coverage=trace-pc is not supported by compiler)
681 CFLAGS_KCOV =
682 endif
683endif
684
676ifeq ($(cc-name),clang) 685ifeq ($(cc-name),clang)
677KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) 686KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
678KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) 687KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8b680a5cb25b..54478b7635de 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -28,6 +28,7 @@ config X86
28 select ARCH_HAS_ELF_RANDOMIZE 28 select ARCH_HAS_ELF_RANDOMIZE
29 select ARCH_HAS_FAST_MULTIPLIER 29 select ARCH_HAS_FAST_MULTIPLIER
30 select ARCH_HAS_GCOV_PROFILE_ALL 30 select ARCH_HAS_GCOV_PROFILE_ALL
31 select ARCH_HAS_KCOV if X86_64
31 select ARCH_HAS_PMEM_API if X86_64 32 select ARCH_HAS_PMEM_API if X86_64
32 select ARCH_HAS_MMIO_FLUSH 33 select ARCH_HAS_MMIO_FLUSH
33 select ARCH_HAS_SG_CHAIN 34 select ARCH_HAS_SG_CHAIN
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 0bf6749522d9..b1ef9e489084 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -12,6 +12,13 @@
12KASAN_SANITIZE := n 12KASAN_SANITIZE := n
13OBJECT_FILES_NON_STANDARD := y 13OBJECT_FILES_NON_STANDARD := y
14 14
15# Kernel does not boot with kcov instrumentation here.
16# One of the problems observed was insertion of __sanitizer_cov_trace_pc()
17# callback into middle of per-cpu data enabling code. Thus the callback observed
18# inconsistent state and crashed. We are interested mostly in syscall coverage,
19# so boot code is not interesting anyway.
20KCOV_INSTRUMENT := n
21
15# If you want to preset the SVGA mode, uncomment the next line and 22# If you want to preset the SVGA mode, uncomment the next line and
16# set SVGA_MODE to whatever number you want. 23# set SVGA_MODE to whatever number you want.
17# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. 24# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 5e1d26e09407..6915ff2bd996 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -19,6 +19,9 @@
19KASAN_SANITIZE := n 19KASAN_SANITIZE := n
20OBJECT_FILES_NON_STANDARD := y 20OBJECT_FILES_NON_STANDARD := y
21 21
22# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
23KCOV_INSTRUMENT := n
24
22targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ 25targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
23 vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 26 vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
24 27
diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index f9fb859c98b9..6874da5f67fc 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -7,6 +7,9 @@ KASAN_SANITIZE := n
7UBSAN_SANITIZE := n 7UBSAN_SANITIZE := n
8OBJECT_FILES_NON_STANDARD := y 8OBJECT_FILES_NON_STANDARD := y
9 9
10# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
11KCOV_INSTRUMENT := n
12
10VDSO64-$(CONFIG_X86_64) := y 13VDSO64-$(CONFIG_X86_64) := y
11VDSOX32-$(CONFIG_X86_X32_ABI) := y 14VDSOX32-$(CONFIG_X86_X32_ABI) := y
12VDSO32-$(CONFIG_X86_32) := y 15VDSO32-$(CONFIG_X86_32) := y
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index d5fb0871aba3..adaae2c781c1 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -25,6 +25,12 @@ OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y
25OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o := y 25OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o := y
26OBJECT_FILES_NON_STANDARD_test_nx.o := y 26OBJECT_FILES_NON_STANDARD_test_nx.o := y
27 27
28# If instrumentation of this dir is enabled, boot hangs during first second.
29# Probably could be more selective here, but note that files related to irqs,
30# boot, dumpstack/stacktrace, etc are either non-interesting or can lead to
31# non-deterministic coverage.
32KCOV_INSTRUMENT := n
33
28CFLAGS_irq.o := -I$(src)/../include/asm/trace 34CFLAGS_irq.o := -I$(src)/../include/asm/trace
29 35
30obj-y := process_$(BITS).o signal.o 36obj-y := process_$(BITS).o signal.o
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 8bb12ddc5db8..8e63ebdcbd0b 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -2,6 +2,10 @@
2# Makefile for local APIC drivers and for the IO-APIC code 2# Makefile for local APIC drivers and for the IO-APIC code
3# 3#
4 4
5# Leads to non-deterministic coverage that is not a function of syscall inputs.
6# In particualr, smp_apic_timer_interrupt() is called in random places.
7KCOV_INSTRUMENT := n
8
5obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o vector.o 9obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o vector.o
6obj-y += hw_nmi.o 10obj-y += hw_nmi.o
7 11
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 0d373d7affc8..4a8697f7d4ef 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -8,6 +8,10 @@ CFLAGS_REMOVE_common.o = -pg
8CFLAGS_REMOVE_perf_event.o = -pg 8CFLAGS_REMOVE_perf_event.o = -pg
9endif 9endif
10 10
11# If these files are instrumented, boot hangs during the first second.
12KCOV_INSTRUMENT_common.o := n
13KCOV_INSTRUMENT_perf_event.o := n
14
11# Make sure load_percpu_segment has no stackprotector 15# Make sure load_percpu_segment has no stackprotector
12nostackp := $(call cc-option, -fno-stack-protector) 16nostackp := $(call cc-option, -fno-stack-protector)
13CFLAGS_common.o := $(nostackp) 17CFLAGS_common.o := $(nostackp)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index a501fa25da41..72a576752a7e 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -2,6 +2,9 @@
2# Makefile for x86 specific library files. 2# Makefile for x86 specific library files.
3# 3#
4 4
5# Produces uninteresting flaky coverage.
6KCOV_INSTRUMENT_delay.o := n
7
5inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk 8inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
6inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt 9inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
7quiet_cmd_inat_tables = GEN $@ 10quiet_cmd_inat_tables = GEN $@
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 67cf2e1e557b..f98913258c63 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -1,3 +1,6 @@
1# Kernel does not boot with instrumentation of tlb.c.
2KCOV_INSTRUMENT_tlb.o := n
3
1obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ 4obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
2 pat.o pgtable.o physaddr.o gup.o setup_nx.o 5 pat.o pgtable.o physaddr.o gup.o setup_nx.o
3 6
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 053abe7b0ef7..b95964610ea7 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -9,6 +9,9 @@
9KASAN_SANITIZE := n 9KASAN_SANITIZE := n
10OBJECT_FILES_NON_STANDARD := y 10OBJECT_FILES_NON_STANDARD := y
11 11
12# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
13KCOV_INSTRUMENT := n
14
12always := realmode.bin realmode.relocs 15always := realmode.bin realmode.relocs
13 16
14wakeup-objs := wakeup_asm.o wakemain.o video-mode.o 17wakeup-objs := wakeup_asm.o wakemain.o video-mode.o
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index a15841eced4e..da99bbb74aeb 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -25,6 +25,9 @@ KASAN_SANITIZE := n
25UBSAN_SANITIZE := n 25UBSAN_SANITIZE := n
26OBJECT_FILES_NON_STANDARD := y 26OBJECT_FILES_NON_STANDARD := y
27 27
28# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
29KCOV_INSTRUMENT := n
30
28lib-y := efi-stub-helper.o 31lib-y := efi-stub-helper.o
29 32
30# include the stub's generic dependencies from lib/ when building for ARM/arm64 33# include the stub's generic dependencies from lib/ when building for ARM/arm64
diff --git a/include/linux/kcov.h b/include/linux/kcov.h
new file mode 100644
index 000000000000..2883ac98c280
--- /dev/null
+++ b/include/linux/kcov.h
@@ -0,0 +1,29 @@
1#ifndef _LINUX_KCOV_H
2#define _LINUX_KCOV_H
3
4#include <uapi/linux/kcov.h>
5
6struct task_struct;
7
8#ifdef CONFIG_KCOV
9
10void kcov_task_init(struct task_struct *t);
11void kcov_task_exit(struct task_struct *t);
12
13enum kcov_mode {
14 /* Coverage collection is not enabled yet. */
15 KCOV_MODE_DISABLED = 0,
16 /*
17 * Tracing coverage collection mode.
18 * Covered PCs are collected in a per-task buffer.
19 */
20 KCOV_MODE_TRACE = 1,
21};
22
23#else
24
25static inline void kcov_task_init(struct task_struct *t) {}
26static inline void kcov_task_exit(struct task_struct *t) {}
27
28#endif /* CONFIG_KCOV */
29#endif /* _LINUX_KCOV_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 084ed9fba620..34495d2d2d7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -51,6 +51,7 @@ struct sched_param {
51#include <linux/resource.h> 51#include <linux/resource.h>
52#include <linux/timer.h> 52#include <linux/timer.h>
53#include <linux/hrtimer.h> 53#include <linux/hrtimer.h>
54#include <linux/kcov.h>
54#include <linux/task_io_accounting.h> 55#include <linux/task_io_accounting.h>
55#include <linux/latencytop.h> 56#include <linux/latencytop.h>
56#include <linux/cred.h> 57#include <linux/cred.h>
@@ -1818,6 +1819,16 @@ struct task_struct {
1818 /* bitmask and counter of trace recursion */ 1819 /* bitmask and counter of trace recursion */
1819 unsigned long trace_recursion; 1820 unsigned long trace_recursion;
1820#endif /* CONFIG_TRACING */ 1821#endif /* CONFIG_TRACING */
1822#ifdef CONFIG_KCOV
1823 /* Coverage collection mode enabled for this task (0 if disabled). */
1824 enum kcov_mode kcov_mode;
1825 /* Size of the kcov_area. */
1826 unsigned kcov_size;
1827 /* Buffer for coverage collection. */
1828 void *kcov_area;
1829 /* kcov desciptor wired with this task or NULL. */
1830 struct kcov *kcov;
1831#endif
1821#ifdef CONFIG_MEMCG 1832#ifdef CONFIG_MEMCG
1822 struct mem_cgroup *memcg_in_oom; 1833 struct mem_cgroup *memcg_in_oom;
1823 gfp_t memcg_oom_gfp_mask; 1834 gfp_t memcg_oom_gfp_mask;
diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h
new file mode 100644
index 000000000000..574e22ec640d
--- /dev/null
+++ b/include/uapi/linux/kcov.h
@@ -0,0 +1,10 @@
1#ifndef _LINUX_KCOV_IOCTLS_H
2#define _LINUX_KCOV_IOCTLS_H
3
4#include <linux/types.h>
5
6#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
7#define KCOV_ENABLE _IO('c', 100)
8#define KCOV_DISABLE _IO('c', 101)
9
10#endif /* _LINUX_KCOV_IOCTLS_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index baa55e50a315..f0c40bf49d9f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -18,6 +18,17 @@ ifdef CONFIG_FUNCTION_TRACER
18CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE) 18CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE)
19endif 19endif
20 20
21# Prevents flicker of uninteresting __do_softirq()/__local_bh_disable_ip()
22# in coverage traces.
23KCOV_INSTRUMENT_softirq.o := n
24# These are called from save_stack_trace() on slub debug path,
25# and produce insane amounts of uninteresting coverage.
26KCOV_INSTRUMENT_module.o := n
27KCOV_INSTRUMENT_extable.o := n
28# Don't self-instrument.
29KCOV_INSTRUMENT_kcov.o := n
30KASAN_SANITIZE_kcov.o := n
31
21# cond_syscall is currently not LTO compatible 32# cond_syscall is currently not LTO compatible
22CFLAGS_sys_ni.o = $(DISABLE_LTO) 33CFLAGS_sys_ni.o = $(DISABLE_LTO)
23 34
@@ -68,6 +79,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
68obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o 79obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o
69obj-$(CONFIG_AUDIT_TREE) += audit_tree.o 80obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
70obj-$(CONFIG_GCOV_KERNEL) += gcov/ 81obj-$(CONFIG_GCOV_KERNEL) += gcov/
82obj-$(CONFIG_KCOV) += kcov.o
71obj-$(CONFIG_KPROBES) += kprobes.o 83obj-$(CONFIG_KPROBES) += kprobes.o
72obj-$(CONFIG_KGDB) += debug/ 84obj-$(CONFIG_KGDB) += debug/
73obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o 85obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
diff --git a/kernel/exit.c b/kernel/exit.c
index 10e088237fed..953d1a1c0387 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -53,6 +53,7 @@
53#include <linux/oom.h> 53#include <linux/oom.h>
54#include <linux/writeback.h> 54#include <linux/writeback.h>
55#include <linux/shm.h> 55#include <linux/shm.h>
56#include <linux/kcov.h>
56 57
57#include <asm/uaccess.h> 58#include <asm/uaccess.h>
58#include <asm/unistd.h> 59#include <asm/unistd.h>
@@ -655,6 +656,7 @@ void do_exit(long code)
655 TASKS_RCU(int tasks_rcu_i); 656 TASKS_RCU(int tasks_rcu_i);
656 657
657 profile_task_exit(tsk); 658 profile_task_exit(tsk);
659 kcov_task_exit(tsk);
658 660
659 WARN_ON(blk_needs_flush_plug(tsk)); 661 WARN_ON(blk_needs_flush_plug(tsk));
660 662
diff --git a/kernel/fork.c b/kernel/fork.c
index 5b8d1e7ceeea..d277e83ed3e0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -75,6 +75,7 @@
75#include <linux/aio.h> 75#include <linux/aio.h>
76#include <linux/compiler.h> 76#include <linux/compiler.h>
77#include <linux/sysctl.h> 77#include <linux/sysctl.h>
78#include <linux/kcov.h>
78 79
79#include <asm/pgtable.h> 80#include <asm/pgtable.h>
80#include <asm/pgalloc.h> 81#include <asm/pgalloc.h>
@@ -392,6 +393,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
392 393
393 account_kernel_stack(ti, 1); 394 account_kernel_stack(ti, 1);
394 395
396 kcov_task_init(tsk);
397
395 return tsk; 398 return tsk;
396 399
397free_ti: 400free_ti:
diff --git a/kernel/kcov.c b/kernel/kcov.c
new file mode 100644
index 000000000000..3efbee0834a8
--- /dev/null
+++ b/kernel/kcov.c
@@ -0,0 +1,273 @@
1#define pr_fmt(fmt) "kcov: " fmt
2
3#include <linux/compiler.h>
4#include <linux/types.h>
5#include <linux/file.h>
6#include <linux/fs.h>
7#include <linux/mm.h>
8#include <linux/printk.h>
9#include <linux/slab.h>
10#include <linux/spinlock.h>
11#include <linux/vmalloc.h>
12#include <linux/debugfs.h>
13#include <linux/uaccess.h>
14#include <linux/kcov.h>
15
16/*
17 * kcov descriptor (one per opened debugfs file).
18 * State transitions of the descriptor:
19 * - initial state after open()
20 * - then there must be a single ioctl(KCOV_INIT_TRACE) call
21 * - then, mmap() call (several calls are allowed but not useful)
22 * - then, repeated enable/disable for a task (only one task a time allowed)
23 */
24struct kcov {
25 /*
26 * Reference counter. We keep one for:
27 * - opened file descriptor
28 * - task with enabled coverage (we can't unwire it from another task)
29 */
30 atomic_t refcount;
31 /* The lock protects mode, size, area and t. */
32 spinlock_t lock;
33 enum kcov_mode mode;
34 /* Size of arena (in long's for KCOV_MODE_TRACE). */
35 unsigned size;
36 /* Coverage buffer shared with user space. */
37 void *area;
38 /* Task for which we collect coverage, or NULL. */
39 struct task_struct *t;
40};
41
42/*
43 * Entry point from instrumented code.
44 * This is called once per basic-block/edge.
45 */
46void __sanitizer_cov_trace_pc(void)
47{
48 struct task_struct *t;
49 enum kcov_mode mode;
50
51 t = current;
52 /*
53 * We are interested in code coverage as a function of a syscall inputs,
54 * so we ignore code executed in interrupts.
55 */
56 if (!t || in_interrupt())
57 return;
58 mode = READ_ONCE(t->kcov_mode);
59 if (mode == KCOV_MODE_TRACE) {
60 unsigned long *area;
61 unsigned long pos;
62
63 /*
64 * There is some code that runs in interrupts but for which
65 * in_interrupt() returns false (e.g. preempt_schedule_irq()).
66 * READ_ONCE()/barrier() effectively provides load-acquire wrt
67 * interrupts, there are paired barrier()/WRITE_ONCE() in
68 * kcov_ioctl_locked().
69 */
70 barrier();
71 area = t->kcov_area;
72 /* The first word is number of subsequent PCs. */
73 pos = READ_ONCE(area[0]) + 1;
74 if (likely(pos < t->kcov_size)) {
75 area[pos] = _RET_IP_;
76 WRITE_ONCE(area[0], pos);
77 }
78 }
79}
80EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
81
82static void kcov_get(struct kcov *kcov)
83{
84 atomic_inc(&kcov->refcount);
85}
86
87static void kcov_put(struct kcov *kcov)
88{
89 if (atomic_dec_and_test(&kcov->refcount)) {
90 vfree(kcov->area);
91 kfree(kcov);
92 }
93}
94
95void kcov_task_init(struct task_struct *t)
96{
97 t->kcov_mode = KCOV_MODE_DISABLED;
98 t->kcov_size = 0;
99 t->kcov_area = NULL;
100 t->kcov = NULL;
101}
102
103void kcov_task_exit(struct task_struct *t)
104{
105 struct kcov *kcov;
106
107 kcov = t->kcov;
108 if (kcov == NULL)
109 return;
110 spin_lock(&kcov->lock);
111 if (WARN_ON(kcov->t != t)) {
112 spin_unlock(&kcov->lock);
113 return;
114 }
115 /* Just to not leave dangling references behind. */
116 kcov_task_init(t);
117 kcov->t = NULL;
118 spin_unlock(&kcov->lock);
119 kcov_put(kcov);
120}
121
122static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
123{
124 int res = 0;
125 void *area;
126 struct kcov *kcov = vma->vm_file->private_data;
127 unsigned long size, off;
128 struct page *page;
129
130 area = vmalloc_user(vma->vm_end - vma->vm_start);
131 if (!area)
132 return -ENOMEM;
133
134 spin_lock(&kcov->lock);
135 size = kcov->size * sizeof(unsigned long);
136 if (kcov->mode == KCOV_MODE_DISABLED || vma->vm_pgoff != 0 ||
137 vma->vm_end - vma->vm_start != size) {
138 res = -EINVAL;
139 goto exit;
140 }
141 if (!kcov->area) {
142 kcov->area = area;
143 vma->vm_flags |= VM_DONTEXPAND;
144 spin_unlock(&kcov->lock);
145 for (off = 0; off < size; off += PAGE_SIZE) {
146 page = vmalloc_to_page(kcov->area + off);
147 if (vm_insert_page(vma, vma->vm_start + off, page))
148 WARN_ONCE(1, "vm_insert_page() failed");
149 }
150 return 0;
151 }
152exit:
153 spin_unlock(&kcov->lock);
154 vfree(area);
155 return res;
156}
157
158static int kcov_open(struct inode *inode, struct file *filep)
159{
160 struct kcov *kcov;
161
162 kcov = kzalloc(sizeof(*kcov), GFP_KERNEL);
163 if (!kcov)
164 return -ENOMEM;
165 atomic_set(&kcov->refcount, 1);
166 spin_lock_init(&kcov->lock);
167 filep->private_data = kcov;
168 return nonseekable_open(inode, filep);
169}
170
171static int kcov_close(struct inode *inode, struct file *filep)
172{
173 kcov_put(filep->private_data);
174 return 0;
175}
176
177static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
178 unsigned long arg)
179{
180 struct task_struct *t;
181 unsigned long size, unused;
182
183 switch (cmd) {
184 case KCOV_INIT_TRACE:
185 /*
186 * Enable kcov in trace mode and setup buffer size.
187 * Must happen before anything else.
188 */
189 if (kcov->mode != KCOV_MODE_DISABLED)
190 return -EBUSY;
191 /*
192 * Size must be at least 2 to hold current position and one PC.
193 * Later we allocate size * sizeof(unsigned long) memory,
194 * that must not overflow.
195 */
196 size = arg;
197 if (size < 2 || size > INT_MAX / sizeof(unsigned long))
198 return -EINVAL;
199 kcov->size = size;
200 kcov->mode = KCOV_MODE_TRACE;
201 return 0;
202 case KCOV_ENABLE:
203 /*
204 * Enable coverage for the current task.
205 * At this point user must have been enabled trace mode,
206 * and mmapped the file. Coverage collection is disabled only
207 * at task exit or voluntary by KCOV_DISABLE. After that it can
208 * be enabled for another task.
209 */
210 unused = arg;
211 if (unused != 0 || kcov->mode == KCOV_MODE_DISABLED ||
212 kcov->area == NULL)
213 return -EINVAL;
214 if (kcov->t != NULL)
215 return -EBUSY;
216 t = current;
217 /* Cache in task struct for performance. */
218 t->kcov_size = kcov->size;
219 t->kcov_area = kcov->area;
220 /* See comment in __sanitizer_cov_trace_pc(). */
221 barrier();
222 WRITE_ONCE(t->kcov_mode, kcov->mode);
223 t->kcov = kcov;
224 kcov->t = t;
225 /* This is put either in kcov_task_exit() or in KCOV_DISABLE. */
226 kcov_get(kcov);
227 return 0;
228 case KCOV_DISABLE:
229 /* Disable coverage for the current task. */
230 unused = arg;
231 if (unused != 0 || current->kcov != kcov)
232 return -EINVAL;
233 t = current;
234 if (WARN_ON(kcov->t != t))
235 return -EINVAL;
236 kcov_task_init(t);
237 kcov->t = NULL;
238 kcov_put(kcov);
239 return 0;
240 default:
241 return -ENOTTY;
242 }
243}
244
245static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
246{
247 struct kcov *kcov;
248 int res;
249
250 kcov = filep->private_data;
251 spin_lock(&kcov->lock);
252 res = kcov_ioctl_locked(kcov, cmd, arg);
253 spin_unlock(&kcov->lock);
254 return res;
255}
256
257static const struct file_operations kcov_fops = {
258 .open = kcov_open,
259 .unlocked_ioctl = kcov_ioctl,
260 .mmap = kcov_mmap,
261 .release = kcov_close,
262};
263
264static int __init kcov_init(void)
265{
266 if (!debugfs_create_file("kcov", 0600, NULL, NULL, &kcov_fops)) {
267 pr_err("failed to create kcov in debugfs\n");
268 return -ENOMEM;
269 }
270 return 0;
271}
272
273device_initcall(kcov_init);
diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile
index 8e96f6cc2a4a..31322a4275cd 100644
--- a/kernel/locking/Makefile
+++ b/kernel/locking/Makefile
@@ -1,3 +1,6 @@
1# Any varying coverage in these files is non-deterministic
2# and is generally not a function of system call inputs.
3KCOV_INSTRUMENT := n
1 4
2obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o 5obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o
3 6
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 61a16569ffbf..032b2c015beb 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -1,3 +1,7 @@
1# Any varying coverage in these files is non-deterministic
2# and is generally not a function of system call inputs.
3KCOV_INSTRUMENT := n
4
1obj-y += update.o sync.o 5obj-y += update.o sync.o
2obj-$(CONFIG_SRCU) += srcu.o 6obj-$(CONFIG_SRCU) += srcu.o
3obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o 7obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 302d6ebd64f7..414d9c16da42 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -2,6 +2,10 @@ ifdef CONFIG_FUNCTION_TRACER
2CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE) 2CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE)
3endif 3endif
4 4
5# These files are disabled because they produce non-interesting flaky coverage
6# that is not a function of syscall inputs. E.g. involuntary context switches.
7KCOV_INSTRUMENT := n
8
5ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) 9ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
6# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is 10# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
7# needed for x86 only. Why this used to be enabled for all architectures is beyond 11# needed for x86 only. Why this used to be enabled for all architectures is beyond
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 5a60f45cd9bb..532d4d52d1df 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -696,6 +696,27 @@ source "lib/Kconfig.kasan"
696 696
697endmenu # "Memory Debugging" 697endmenu # "Memory Debugging"
698 698
699config ARCH_HAS_KCOV
700 bool
701 help
702 KCOV does not have any arch-specific code, but currently it is enabled
703 only for x86_64. KCOV requires testing on other archs, and most likely
704 disabling of instrumentation for some early boot code.
705
706config KCOV
707 bool "Code coverage for fuzzing"
708 depends on ARCH_HAS_KCOV
709 select DEBUG_FS
710 help
711 KCOV exposes kernel code coverage information in a form suitable
712 for coverage-guided fuzzing (randomized testing).
713
714 If RANDOMIZE_BASE is enabled, PC values will not be stable across
715 different machines and across reboots. If you need stable PC values,
716 disable RANDOMIZE_BASE.
717
718 For more details, see Documentation/kcov.txt.
719
699config DEBUG_SHIRQ 720config DEBUG_SHIRQ
700 bool "Debug shared IRQ handlers" 721 bool "Debug shared IRQ handlers"
701 depends on DEBUG_KERNEL 722 depends on DEBUG_KERNEL
diff --git a/lib/Makefile b/lib/Makefile
index 4962d14c450f..a1de5b61ff40 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -7,6 +7,18 @@ ORIG_CFLAGS := $(KBUILD_CFLAGS)
7KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) 7KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
8endif 8endif
9 9
10# These files are disabled because they produce lots of non-interesting and/or
11# flaky coverage that is not a function of syscall inputs. For example,
12# rbtree can be global and individual rotations don't correlate with inputs.
13KCOV_INSTRUMENT_string.o := n
14KCOV_INSTRUMENT_rbtree.o := n
15KCOV_INSTRUMENT_list_debug.o := n
16KCOV_INSTRUMENT_debugobjects.o := n
17KCOV_INSTRUMENT_dynamic_debug.o := n
18# Kernel does not boot if we instrument this file as it uses custom calling
19# convention (see CONFIG_ARCH_HWEIGHT_CFLAGS).
20KCOV_INSTRUMENT_hweight.o := n
21
10lib-y := ctype.o string.o vsprintf.o cmdline.o \ 22lib-y := ctype.o string.o vsprintf.o cmdline.o \
11 rbtree.o radix-tree.o dump_stack.o timerqueue.o\ 23 rbtree.o radix-tree.o dump_stack.o timerqueue.o\
12 idr.o int_sqrt.o extable.o \ 24 idr.o int_sqrt.o extable.o \
diff --git a/mm/Makefile b/mm/Makefile
index 6da300a1414b..f5e797cbd128 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -5,6 +5,21 @@
5KASAN_SANITIZE_slab_common.o := n 5KASAN_SANITIZE_slab_common.o := n
6KASAN_SANITIZE_slub.o := n 6KASAN_SANITIZE_slub.o := n
7 7
8# These files are disabled because they produce non-interesting and/or
9# flaky coverage that is not a function of syscall inputs. E.g. slab is out of
10# free pages, or a task is migrated between nodes.
11KCOV_INSTRUMENT_slab_common.o := n
12KCOV_INSTRUMENT_slob.o := n
13KCOV_INSTRUMENT_slab.o := n
14KCOV_INSTRUMENT_slub.o := n
15KCOV_INSTRUMENT_page_alloc.o := n
16KCOV_INSTRUMENT_debug-pagealloc.o := n
17KCOV_INSTRUMENT_kmemleak.o := n
18KCOV_INSTRUMENT_kmemcheck.o := n
19KCOV_INSTRUMENT_memcontrol.o := n
20KCOV_INSTRUMENT_mmzone.o := n
21KCOV_INSTRUMENT_vmstat.o := n
22
8mmu-y := nommu.o 23mmu-y := nommu.o
9mmu-$(CONFIG_MMU) := gup.o highmem.o memory.o mincore.o \ 24mmu-$(CONFIG_MMU) := gup.o highmem.o memory.o mincore.o \
10 mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \ 25 mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile
index a61460d9f5b0..131daadf40e4 100644
--- a/mm/kasan/Makefile
+++ b/mm/kasan/Makefile
@@ -1,5 +1,6 @@
1KASAN_SANITIZE := n 1KASAN_SANITIZE := n
2UBSAN_SANITIZE_kasan.o := n 2UBSAN_SANITIZE_kasan.o := n
3KCOV_INSTRUMENT := n
3 4
4CFLAGS_REMOVE_kasan.o = -pg 5CFLAGS_REMOVE_kasan.o = -pg
5# Function splitter causes unnecessary splits in __asan_load1/__asan_store1 6# Function splitter causes unnecessary splits in __asan_load1/__asan_store1
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index ad50d5859ac4..ddf83d0181e7 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -136,6 +136,12 @@ _c_flags += $(if $(patsubst n%,, \
136 $(CFLAGS_UBSAN)) 136 $(CFLAGS_UBSAN))
137endif 137endif
138 138
139ifeq ($(CONFIG_KCOV),y)
140_c_flags += $(if $(patsubst n%,, \
141 $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)y), \
142 $(CFLAGS_KCOV))
143endif
144
139# If building the kernel in a separate objtree expand all occurrences 145# If building the kernel in a separate objtree expand all occurrences
140# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). 146# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
141 147