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). 112