diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-11-30 17:49:55 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-11-30 20:25:07 +0100 |
| commit | 6e47fcbddef51e3f135b21dffd648c3899e5cec5 (patch) | |
| tree | c8f694ca1f0008724005672b9821326bf3a89ad1 /tools/kcovfuzzer | |
| parent | 5effceb76a54185ae584abfe1d8ec0406d1f917a (diff) | |
tools/kcovfuzzer: refactor for easier addition of new fuzzers
Currently it's completely unstructured, a single "main" function.
Make it reasonably structured with the goal of easier addition
of new fuzzers.
Diffstat (limited to 'tools/kcovfuzzer')
| -rw-r--r-- | tools/kcovfuzzer/kcovfuzzer.c | 128 |
1 files changed, 78 insertions, 50 deletions
diff --git a/tools/kcovfuzzer/kcovfuzzer.c b/tools/kcovfuzzer/kcovfuzzer.c index ae3355b72..eadd77ad7 100644 --- a/tools/kcovfuzzer/kcovfuzzer.c +++ b/tools/kcovfuzzer/kcovfuzzer.c @@ -1,8 +1,8 @@ // KCOV glue for libfuzzer. Build as: -// clang libfuzzer_kcov.c -fsanitize=fuzzer -Wall -o fuzzer +// clang tools/kcovfuzzer/kcovfuzzer.c -fsanitize=fuzzer -Wall -o fuzzer // Run as: -// ./fuzzer -max_len=129 corpus-bpf -// ./fuzzer -max_len=100 -only_ascii=1 corpus-filter +// KCOVFUZZER=bpf ./fuzzer -max_len=129 corpus_bpf +// KCOVFUZZER=trace_filter ./fuzzer -max_len=100 -only_ascii=1 corpus_trace_filter // If you need to build with -static, then the following env needs to be exported: // UBSAN_OPTIONS="handle_segv=0 handle_sigbus=0 handle_abort=0 handle_sigill=0 handle_sigtrap=0 handle_sigfpe=0" // and the following flags added to fuzzer invocation: @@ -25,45 +25,20 @@ #include <sys/types.h> #include <unistd.h> -#define KCOV_COVER_SIZE (256 << 10) -#define KCOV_TRACE_PC 0 -#define KCOV_INIT_TRACE64 _IOR('c', 1, uint64_t) -#define KCOV_ENABLE _IO('c', 100) +void init(const char*, long); +void (*fuzz_func)(const char*, long) = init; +void fail(const char* msg, ...); +void cover_start(); +void cover_stop(); -__attribute__((section("__libfuzzer_extra_counters"))) unsigned char libfuzzer_coverage[32 << 10]; - -void fail(const char* msg, ...) +int LLVMFuzzerTestOneInput(const char* data, long size) { - int e = errno; - va_list args; - va_start(args, msg); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, " (errno %d)\n", e); - _exit(1); + fuzz_func(data, size); + return 0; } -#define FUZZ_BPF 1 -//#define FUZZ_TRACE_FILTER 1 - -int LLVMFuzzerTestOneInput(const char* data, long size) +void bpf(const char* data, long size) { - static int kcov = -1; - static uint64_t* kcov_data; - if (kcov == -1) { - kcov = open("/sys/kernel/debug/kcov", O_RDWR); - if (kcov == -1) - fail("open of /sys/kernel/debug/kcov failed"); - if (ioctl(kcov, KCOV_INIT_TRACE64, KCOV_COVER_SIZE)) - fail("cover init trace write failed"); - kcov_data = (uint64_t*)mmap(NULL, KCOV_COVER_SIZE * sizeof(kcov_data[0]), - PROT_READ | PROT_WRITE, MAP_SHARED, kcov, 0); - if (kcov_data == MAP_FAILED) - fail("cover mmap failed"); - if (ioctl(kcov, KCOV_ENABLE, KCOV_TRACE_PC)) - fail("cover enable write trace failed"); - } -#ifdef FUZZ_BPF union bpf_attr attr; memset(&attr, 0, sizeof(attr)); attr.map_type = BPF_MAP_TYPE_HASH; @@ -78,14 +53,20 @@ int LLVMFuzzerTestOneInput(const char* data, long size) attr.insn_cnt = size / 8; attr.license = (uint64_t) "GPL"; - __atomic_store_n(&kcov_data[0], 0, __ATOMIC_RELAXED); + cover_start(); int pfd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); if (pfd != -1) { memset(&attr, 0, sizeof(attr)); attr.test.prog_fd = pfd; syscall(SYS_bpf, BPF_PROG_TEST_RUN, &attr, sizeof(attr)); } -#elif FUZZ_TRACE_FILTER + cover_stop(); + close(pfd); + close(mfd); +} + +void trace_filter(const char* data, long size) +{ int fd0 = open("/sys/kernel/debug/tracing/events/syscalls/sys_exit_read/enable", O_RDWR); if (fd0 == -1) fail("open enable failed"); @@ -95,7 +76,7 @@ int LLVMFuzzerTestOneInput(const char* data, long size) int fd2 = open("/sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger", O_RDWR); if (fd2 == -1) fail("open trigger failed"); - __atomic_store_n(&kcov_data[0], 0, __ATOMIC_RELAXED); + cover_start(); char buf[256]; buf[0] = '1'; write(fd0, buf, 1); @@ -107,7 +88,53 @@ int LLVMFuzzerTestOneInput(const char* data, long size) read(fd2, buf, sizeof(buf)); buf[0] = '0'; write(fd0, buf, 1); -#endif + cover_stop(); + close(fd0); + close(fd1); + close(fd2); +} + +#define KCOV_COVER_SIZE (256 << 10) +#define KCOV_TRACE_PC 0 +#define KCOV_INIT_TRACE64 _IOR('c', 1, uint64_t) +#define KCOV_ENABLE _IO('c', 100) + +__attribute__((section("__libfuzzer_extra_counters"))) unsigned char libfuzzer_coverage[32 << 10]; +uint64_t* kcov_data; + +void init(const char* data, long size) +{ + const char* name = getenv("KCOVFUZZER"); + if (strcmp(name, "bpf") == 0) + fuzz_func = bpf; + else if (strcmp(name, "trace_filter") == 0) + fuzz_func = trace_filter; + else + fail("unknown fuzz function '%s'", name); + + int kcov = open("/sys/kernel/debug/kcov", O_RDWR); + if (kcov == -1) + fail("open of /sys/kernel/debug/kcov failed"); + if (ioctl(kcov, KCOV_INIT_TRACE64, KCOV_COVER_SIZE)) + fail("cover init trace write failed"); + kcov_data = (uint64_t*)mmap(NULL, KCOV_COVER_SIZE * sizeof(kcov_data[0]), + PROT_READ | PROT_WRITE, MAP_SHARED, kcov, 0); + if (kcov_data == MAP_FAILED) + fail("cover mmap failed"); + if (ioctl(kcov, KCOV_ENABLE, KCOV_TRACE_PC)) + fail("cover enable write trace failed"); + close(kcov); + + fuzz_func(data, size); +} + +void cover_start() +{ + __atomic_store_n(&kcov_data[0], 0, __ATOMIC_RELAXED); +} + +void cover_stop() +{ uint64_t ncov = __atomic_load_n(&kcov_data[0], __ATOMIC_RELAXED); if (ncov >= KCOV_COVER_SIZE) fail("too much cover: %llu", ncov); @@ -115,14 +142,15 @@ int LLVMFuzzerTestOneInput(const char* data, long size) uint64_t pc = __atomic_load_n(&kcov_data[i + 1], __ATOMIC_RELAXED); libfuzzer_coverage[pc % sizeof(libfuzzer_coverage)]++; } -#ifdef FUZZ_BPF +} - close(pfd); - close(mfd); -#elif FUZZ_TRACE_FILTER - close(fd0); - close(fd1); - close(fd2); -#endif - return 0; +void fail(const char* msg, ...) +{ + int e = errno; + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, " (errno %d)\n", e); + _exit(1); } |
