aboutsummaryrefslogtreecommitdiffstats
path: root/executor/executor_linux.h
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2018-11-22 19:04:06 +0100
committerAndrey Konovalov <andreyknvl@gmail.com>2019-01-16 19:19:53 +0100
commitb5df78dc5d994bc61f1ecee2c5c85313178f392e (patch)
treec285f3be9e8d0ef32e607186ec9ce9eae6901cce /executor/executor_linux.h
parentc0d4a12ee72a2279eada43d9476d2f8a074c3818 (diff)
all: support extra coverage
Right now syzkaller only supports coverage collected from the threads that execute syscalls. However some useful things happen in background threads, and it would be nice to collect coverage from those threads as well. This change adds extra coverage support to syzkaller. This coverage is not associated with a particular syscall, but rather with the whole program. Executor passes extra coverage over the same ipc mechanism to syz-fuzzer with syscall number set to -1. syz-fuzzer then passes this coverage to syz-manager with the call name "extra". This change requires the following kcov patch: https://github.com/xairy/linux/pull/2
Diffstat (limited to 'executor/executor_linux.h')
-rw-r--r--executor/executor_linux.h51
1 files changed, 41 insertions, 10 deletions
diff --git a/executor/executor_linux.h b/executor/executor_linux.h
index c7af48144..68b143ba0 100644
--- a/executor/executor_linux.h
+++ b/executor/executor_linux.h
@@ -11,13 +11,30 @@
#include <sys/syscall.h>
#include <unistd.h>
+const unsigned long KCOV_TRACE_PC = 0;
+const unsigned long KCOV_TRACE_CMP = 1;
+
+template <int N>
+struct kcov_remote_arg {
+ unsigned trace_mode;
+ unsigned area_size;
+ unsigned num_handles;
+ __u64 common_handle;
+ __u64 handles[N];
+};
+
#define KCOV_INIT_TRACE32 _IOR('c', 1, uint32)
#define KCOV_INIT_TRACE64 _IOR('c', 1, uint64)
#define KCOV_ENABLE _IO('c', 100)
#define KCOV_DISABLE _IO('c', 101)
+#define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg<0>)
-const unsigned long KCOV_TRACE_PC = 0;
-const unsigned long KCOV_TRACE_CMP = 1;
+#define KCOV_REMOTE_HANDLE_USB 0x4242000000000000ull
+
+static inline __u64 kcov_remote_handle_usb(int bus)
+{
+ return KCOV_REMOTE_HANDLE_USB + (__u64)bus;
+}
static bool detect_kernel_bitness();
@@ -38,7 +55,7 @@ static long execute_syscall(const call_t* c, long a[kMaxArgs])
return syscall(c->sys_nr, a[0], a[1], a[2], a[3], a[4], a[5]);
}
-static void cover_open(cover_t* cov)
+static void cover_open(cover_t* cov, bool extra)
{
int fd = open("/sys/kernel/debug/kcov", O_RDWR);
if (fd == -1)
@@ -47,9 +64,10 @@ static void cover_open(cover_t* cov)
fail("filed to dup2(%d, %d) cover fd", fd, cov->fd);
close(fd);
const int kcov_init_trace = is_kernel_64_bit ? KCOV_INIT_TRACE64 : KCOV_INIT_TRACE32;
- if (ioctl(cov->fd, kcov_init_trace, kCoverSize))
+ const int cover_size = extra ? kExtraCoverSize : kCoverSize;
+ if (ioctl(cov->fd, kcov_init_trace, cover_size))
fail("cover init trace write failed");
- size_t mmap_alloc_size = kCoverSize * (is_kernel_64_bit ? 8 : 4);
+ size_t mmap_alloc_size = cover_size * (is_kernel_64_bit ? 8 : 4);
cov->data = (char*)mmap(NULL, mmap_alloc_size,
PROT_READ | PROT_WRITE, MAP_SHARED, cov->fd, 0);
if (cov->data == MAP_FAILED)
@@ -57,15 +75,28 @@ static void cover_open(cover_t* cov)
cov->data_end = cov->data + mmap_alloc_size;
}
-static void cover_enable(cover_t* cov, bool collect_comps)
+static void cover_enable(cover_t* cov, bool collect_comps, bool extra)
{
int kcov_mode = collect_comps ? KCOV_TRACE_CMP : KCOV_TRACE_PC;
- // This should be fatal,
+ // The KCOV_ENABLE call should be fatal,
// but in practice ioctl fails with assorted errors (9, 14, 25),
// so we use exitf.
- if (ioctl(cov->fd, KCOV_ENABLE, kcov_mode))
- exitf("cover enable write trace failed, mode=%d", kcov_mode);
- current_cover = cov;
+ if (!extra) {
+ if (ioctl(cov->fd, KCOV_ENABLE, kcov_mode))
+ exitf("cover enable write trace failed, mode=%d", kcov_mode);
+ current_cover = cov;
+ return;
+ }
+ struct kcov_remote_arg<1> arg;
+ memset(&arg, 0, sizeof(arg));
+ arg.trace_mode = kcov_mode;
+ // Coverage buffer size of remote threads.
+ arg.area_size = kExtraCoverSize * (is_kernel_64_bit ? 8 : 4);
+ arg.num_handles = 1;
+ arg.handles[0] = kcov_remote_handle_usb(procid);
+ arg.common_handle = procid + 1;
+ if (ioctl(cov->fd, KCOV_REMOTE_ENABLE, &arg))
+ exitf("cover enable write trace failed");
}
static void cover_reset(cover_t* cov)