]>
Commit | Line | Data |
---|---|---|
5c9a8750 DV |
1 | kcov: code coverage for fuzzing |
2 | =============================== | |
3 | ||
4 | kcov exposes kernel code coverage information in a form suitable for coverage- | |
5 | guided fuzzing (randomized testing). Coverage data of a running kernel is | |
6 | exported via the "kcov" debugfs file. Coverage collection is enabled on a task | |
7 | basis, and thus it can capture precise coverage of a single system call. | |
8 | ||
9 | Note that kcov does not aim to collect as much coverage as possible. It aims | |
10 | to collect more or less stable coverage that is function of syscall inputs. | |
11 | To achieve this goal it does not collect coverage in soft/hard interrupts | |
12 | and instrumentation of some inherently non-deterministic parts of kernel is | |
13 | disbled (e.g. scheduler, locking). | |
14 | ||
15 | Usage: | |
16 | ====== | |
17 | ||
18 | Configure kernel with: | |
19 | ||
20 | CONFIG_KCOV=y | |
21 | ||
22 | CONFIG_KCOV requires gcc built on revision 231296 or later. | |
23 | Profiling data will only become accessible once debugfs has been mounted: | |
24 | ||
25 | mount -t debugfs none /sys/kernel/debug | |
26 | ||
27 | The 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 | ||
45 | int 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 | ||
88 | After piping through addr2line output of the program looks as follows: | |
89 | ||
90 | SyS_read | |
91 | fs/read_write.c:562 | |
92 | __fdget_pos | |
93 | fs/file.c:774 | |
94 | __fget_light | |
95 | fs/file.c:746 | |
96 | __fget_light | |
97 | fs/file.c:750 | |
98 | __fget_light | |
99 | fs/file.c:760 | |
100 | __fdget_pos | |
101 | fs/file.c:784 | |
102 | SyS_read | |
103 | fs/read_write.c:562 | |
104 | ||
105 | If a program needs to collect coverage from several threads (independently), | |
106 | it needs to open /sys/kernel/debug/kcov in each thread separately. | |
107 | ||
108 | The interface is fine-grained to allow efficient forking of test processes. | |
109 | That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, | |
110 | mmaps coverage buffer and then forks child processes in a loop. Child processes | |
111 | only need to enable coverage (disable happens automatically on thread end). |