diff options
author | Patrick Meyer <git@the-space.agency> | 2021-06-06 16:15:07 -0700 |
---|---|---|
committer | Gunnar Beutner <gunnar@beutner.name> | 2021-07-26 17:40:28 +0200 |
commit | 83f88df7574c41bd3c7255d7f46930eef6744b6b (patch) | |
tree | 4ec44f915b8c0c38f07493d344b39d8e71eac948 /Userland/Utilities | |
parent | 67b3255fe84324e384a52e19fb5233ccb3665c1d (diff) | |
download | serenity-83f88df7574c41bd3c7255d7f46930eef6744b6b.zip |
Kernel: Add option to build with coverage instrumentation and KCOV
GCC and Clang allow us to inject a call to a function named
__sanitizer_cov_trace_pc on every edge. This function has to be defined
by us. By noting down the caller in that function we can trace the code
we have encountered during execution. Such information is used by
coverage guided fuzzers like AFL and LibFuzzer to determine if a new
input resulted in a new code path. This makes fuzzing much more
effective.
Additionally this adds a basic KCOV implementation. KCOV is an API that
allows user space to request the kernel to start collecting coverage
information for a given user space thread. Furthermore KCOV then exposes
the collected program counters to user space via a BlockDevice which can
be mmaped from user space.
This work is required to add effective support for fuzzing SerenityOS to
the Syzkaller syscall fuzzer. :^) :^)
Diffstat (limited to 'Userland/Utilities')
-rw-r--r-- | Userland/Utilities/kcov-example.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/Userland/Utilities/kcov-example.cpp b/Userland/Utilities/kcov-example.cpp new file mode 100644 index 0000000000..3bff9728bd --- /dev/null +++ b/Userland/Utilities/kcov-example.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, Patrick Meyer <git@the-space.agency> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <fcntl.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/ioctl_numbers.h> +#include <sys/kcov.h> +#include <sys/mman.h> +#include <unistd.h> + +// Note: This program requires serenity to be built with the CMake build option +// ENABLE_KERNEL_COVERAGE_COLLECTION +int main(void) +{ + constexpr size_t num_entries = 1024 * 100; + + int fd = open("/dev/kcov", O_RDWR); + if (fd == -1) { + perror("open"); + return 1; + } + if (ioctl(fd, KCOV_SETBUFSIZE, num_entries) == -1) { + perror("ioctl: KCOV_SETBUFSIZE"); + return 1; + } + kcov_pc_t* cover = (kcov_pc_t*)mmap(NULL, num_entries * KCOV_ENTRY_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (cover == MAP_FAILED) { + perror("mmap"); + return 1; + } + if (ioctl(fd, KCOV_ENABLE) == -1) { + perror("ioctl: KCOV_ENABLE"); + return 1; + } + cover[0] = 0; + + // Example syscall so we actually cover some kernel code. + getppid(); + + if (ioctl(fd, KCOV_DISABLE) == -1) { + perror("ioctl: KCOV_DISABLE"); + return 1; + } + u64 cov_idx = cover[0]; + for (size_t idx = 1; idx <= cov_idx; idx++) + printf("%p\n", (void*)cover[idx]); + if (munmap(const_cast<u64*>(cover), num_entries * KCOV_ENTRY_SIZE) == -1) { + perror("munmap"); + return 1; + } + close(fd); + + return 0; +} |