aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-06-21 11:03:53 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-06-22 16:40:45 +0200
commitc31f96a8c65c0757078ea77218905c73fc1068d4 (patch)
treefc68a43058ed05e9604514c67240f6a4fa0b25ed
parent14e6c472f54ac36d5bdfe451371c619953eb0a17 (diff)
executor: rework fallback coverage
We have fallback coverage implmentation for freebsd. 1. It's broken after some recent changes. 2. We need it for fuchsia, windows, akaros, linux too. 3. It's painful to work with C code. Move fallback coverage to ipc package, fix it and provide for all OSes.
-rw-r--r--executor/common_linux.h4
-rw-r--r--executor/executor.h42
-rw-r--r--executor/executor_akaros.cc7
-rw-r--r--executor/executor_bsd.cc30
-rw-r--r--executor/executor_fuchsia.cc5
-rw-r--r--executor/executor_linux.cc15
-rw-r--r--executor/executor_windows.cc5
-rw-r--r--executor/syscalls_akaros.h2
-rw-r--r--executor/syscalls_freebsd.h2
-rw-r--r--executor/syscalls_fuchsia.h4
-rw-r--r--executor/syscalls_linux.h10
-rw-r--r--executor/syscalls_netbsd.h2
-rw-r--r--executor/syscalls_test.h4
-rw-r--r--executor/syscalls_windows.h2
-rw-r--r--pkg/csource/linux_common.go4
-rw-r--r--pkg/host/host_freebsd.go4
-rw-r--r--pkg/ipc/ipc.go22
-rw-r--r--sys/syz-sysgen/sysgen.go6
-rw-r--r--sys/targets/targets.go2
-rw-r--r--syz-fuzzer/fuzzer.go54
-rw-r--r--syz-fuzzer/proc.go3
-rw-r--r--syz-fuzzer/testing.go7
-rw-r--r--syz-manager/manager.go48
-rw-r--r--vm/gvisor/gvisor.go2
24 files changed, 154 insertions, 132 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index abfccdd6e..66247a952 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -1961,7 +1961,7 @@ extern unsigned long long procid;
#if defined(SYZ_EXECUTOR)
void reply_handshake();
-void receive_execute(bool need_prog);
+void receive_execute();
void reply_execute(int status);
extern uint32* output_data;
extern uint32* output_pos;
@@ -2030,7 +2030,7 @@ static void loop()
// TODO: consider moving the read into the child.
// Potentially it can speed up things a bit -- when the read finishes
// we already have a forked worker process.
- receive_execute(false);
+ receive_execute();
#endif
int pid = fork();
if (pid < 0)
diff --git a/executor/executor.h b/executor/executor.h
index d5122cc71..15e1aa40b 100644
--- a/executor/executor.h
+++ b/executor/executor.h
@@ -86,7 +86,6 @@ struct thread_t {
osthread_t th;
char* cover_data;
char* cover_end;
- uint64 cover_buffer[1]; // fallback coverage buffer
event_t ready;
event_t done;
@@ -182,11 +181,25 @@ bool copyout(char* addr, uint64 size, uint64* res);
void cover_open();
void cover_enable(thread_t* th);
void cover_reset(thread_t* th);
-uint32 read_cover_size(thread_t* th);
+uint32 cover_read_size(thread_t* th);
bool cover_check(uint32 pc);
bool cover_check(uint64 pc);
static uint32 hash(uint32 a);
static bool dedup(uint32 sig);
+void setup_control_pipes();
+void receive_handshake();
+void receive_execute();
+
+void main_init()
+{
+ setup_control_pipes();
+ if (SYZ_EXECUTOR_USES_FORK_SERVER)
+ receive_handshake();
+ else
+ receive_execute();
+ if (flag_cover)
+ cover_open();
+}
void setup_control_pipes()
{
@@ -235,7 +248,7 @@ void reply_handshake()
fail("control pipe write failed");
}
-void receive_execute(bool need_prog)
+void receive_execute()
{
execute_req req;
if (read(kInPipeFd, &req, sizeof(req)) != (ssize_t)sizeof(req))
@@ -260,11 +273,13 @@ void receive_execute(bool need_prog)
procid, flag_threaded, flag_collide, flag_collect_cover, flag_collect_comps,
flag_dedup_cover, flag_inject_fault, flag_fault_call, flag_fault_nth,
req.prog_size);
- if (req.prog_size == 0) {
- if (need_prog)
+ if (SYZ_EXECUTOR_USES_SHMEM) {
+ if (req.prog_size)
fail("need_prog: no program");
return;
}
+ if (req.prog_size == 0)
+ fail("need_prog: no program");
uint64 pos = 0;
for (;;) {
ssize_t rv = read(kInPipeFd, input_data + pos, sizeof(input_data) - pos);
@@ -301,7 +316,7 @@ void execute_one()
retry:
uint64* input_pos = (uint64*)input_data;
- if (!colliding && !flag_threaded)
+ if (flag_cover && !colliding && !flag_threaded)
cover_enable(&threads[0]);
int call_index = 0;
@@ -499,8 +514,10 @@ void write_coverage_signal(thread_t* th, uint32* signal_count_pos, uint32* cover
cover_t prev = 0;
for (uint32 i = 0; i < th->cover_size; i++) {
cover_t pc = cover_data[i];
- if (!cover_check(pc))
+ if (!cover_check(pc)) {
+ debug("got bad pc: 0x%llx\n", (uint64)pc);
doexit(0);
+ }
cover_t sig = pc ^ prev;
prev = hash(pc);
if (dedup(sig))
@@ -591,7 +608,7 @@ void handle_completion(thread_t* th)
}
// Write out number of comparisons.
*comps_count_pos = comps_size;
- } else {
+ } else if (flag_cover) {
if (is_kernel_64_bit)
write_coverage_signal<uint64>(th, signal_count_pos, cover_count_pos);
else
@@ -623,7 +640,8 @@ void* worker_thread(void* arg)
{
thread_t* th = (thread_t*)arg;
- cover_enable(th);
+ if (flag_cover)
+ cover_enable(th);
for (;;) {
event_wait(&th->ready);
execute_call(th);
@@ -651,7 +669,8 @@ void execute_call(thread_t* th)
fail_fd = inject_fault(flag_fault_nth);
}
- cover_reset(th);
+ if (flag_cover)
+ cover_reset(th);
errno = 0;
th->res = execute_syscall(call, th->args[0], th->args[1], th->args[2],
th->args[3], th->args[4], th->args[5],
@@ -659,7 +678,8 @@ void execute_call(thread_t* th)
th->reserrno = errno;
if (th->res == -1 && th->reserrno == 0)
th->reserrno = EINVAL; // our syz syscalls may misbehave
- th->cover_size = read_cover_size(th);
+ if (flag_cover)
+ th->cover_size = cover_read_size(th);
th->fault_injected = false;
if (flag_inject_fault && th->call_index == flag_fault_call) {
diff --git a/executor/executor_akaros.cc b/executor/executor_akaros.cc
index 1b690f2b9..e13719609 100644
--- a/executor/executor_akaros.cc
+++ b/executor/executor_akaros.cc
@@ -29,12 +29,11 @@ int main(int argc, char** argv)
use_temporary_dir();
install_segv_handler();
- setup_control_pipes();
- receive_handshake();
+ main_init();
reply_handshake();
for (;;) {
- receive_execute(true);
+ receive_execute();
char cwdbuf[128] = "/syz-tmpXXXXXX";
mkdtemp(cwdbuf);
int pid = fork();
@@ -91,7 +90,7 @@ void cover_reset(thread_t* th)
{
}
-uint32 read_cover_size(thread_t* th)
+uint32 cover_read_size(thread_t* th)
{
return 0;
}
diff --git a/executor/executor_bsd.cc b/executor/executor_bsd.cc
index 4ae2cf223..d23f93fb8 100644
--- a/executor/executor_bsd.cc
+++ b/executor/executor_bsd.cc
@@ -89,13 +89,11 @@ int main(int argc, char** argv)
setrlimit(RLIMIT_CORE, &rlim);
install_segv_handler();
- setup_control_pipes();
- receive_handshake();
+ main_init();
reply_handshake();
- cover_open();
for (;;) {
- receive_execute(false);
+ receive_execute();
char cwdbuf[128] = "/syz-tmpXXXXXX";
if (!mkdtemp(cwdbuf))
fail("mkdtemp failed");
@@ -153,11 +151,9 @@ long execute_syscall(const call_t* c, long a0, long a1, long a2, long a3, long a
void cover_open()
{
- if (!flag_cover)
- return;
+#if defined(__FreeBSD__)
for (int i = 0; i < kMaxThreads; i++) {
thread_t* th = &threads[i];
-#if defined(__FreeBSD__)
th->cover_fd = open("/dev/kcov", O_RDWR);
if (th->cover_fd == -1)
fail("open of /dev/kcov failed");
@@ -171,18 +167,13 @@ void cover_open()
fail("cover mmap failed");
th->cover_data = mmap_ptr;
th->cover_end = mmap_ptr + mmap_alloc_size;
-#else
- th->cover_data = (char*)&th->cover_buffer[0];
- th->cover_end = th->cover_data + sizeof(th->cover_buffer);
-#endif
}
+#endif
}
void cover_enable(thread_t* th)
{
#if defined(__FreeBSD__)
- if (!flag_cover)
- return;
debug("#%d: enabling /dev/kcov\n", th->id);
int kcov_mode = flag_collect_comps ? KCOV_MODE_TRACE_CMP : KCOV_MODE_TRACE_PC;
if (ioctl(th->cover_fd, KIOENABLE, &kcov_mode))
@@ -194,17 +185,12 @@ void cover_enable(thread_t* th)
void cover_reset(thread_t* th)
{
#if defined(__FreeBSD__)
- if (!flag_cover)
- return;
-
*th->cover_size_ptr = 0;
#endif
}
-uint32 read_cover_size(thread_t* th)
+uint32 cover_read_size(thread_t* th)
{
- if (!flag_cover)
- return 0;
#if defined(__FreeBSD__)
uint64 size = *th->cover_size_ptr;
debug("#%d: read cover size = %llu\n", th->id, size);
@@ -212,11 +198,7 @@ uint32 read_cover_size(thread_t* th)
fail("#%d: too much cover %llu", th->id, size);
return size;
#else
- // Fallback coverage since we have no real coverage available.
- // We use syscall number or-ed with returned errno value as signal.
- // At least this gives us all combinations of syscall+errno.
- th->cover_data[0] = (th->call_num << 16) | ((th->res == -1 ? th->reserrno : 0) & 0x3ff);
- return 1;
+ return 0;
#endif
}
diff --git a/executor/executor_fuchsia.cc b/executor/executor_fuchsia.cc
index 6c7657732..c21198449 100644
--- a/executor/executor_fuchsia.cc
+++ b/executor/executor_fuchsia.cc
@@ -25,8 +25,7 @@ int main(int argc, char** argv)
fail("mmap of data segment failed");
install_segv_handler();
- setup_control_pipes();
- receive_execute(true);
+ main_init();
execute_one();
return 0;
}
@@ -53,7 +52,7 @@ void cover_reset(thread_t* th)
{
}
-uint32 read_cover_size(thread_t* th)
+uint32 cover_read_size(thread_t* th)
{
return 0;
}
diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc
index f0bccd949..5325a84d2 100644
--- a/executor/executor_linux.cc
+++ b/executor/executor_linux.cc
@@ -72,10 +72,7 @@ int main(int argc, char** argv)
// That's also the reason why we close kInPipeFd/kOutPipeFd below.
close(kInFd);
close(kOutFd);
- setup_control_pipes();
- receive_handshake();
-
- cover_open();
+ main_init();
install_segv_handler();
use_temporary_dir();
@@ -133,8 +130,6 @@ long execute_syscall(const call_t* c, long a0, long a1, long a2, long a3, long a
void cover_open()
{
- if (!flag_cover)
- return;
for (int i = 0; i < kMaxThreads; i++) {
thread_t* th = &threads[i];
th->cover_fd = open("/sys/kernel/debug/kcov", O_RDWR);
@@ -154,8 +149,6 @@ void cover_open()
void cover_enable(thread_t* th)
{
- if (!flag_cover)
- return;
debug("#%d: enabling /sys/kernel/debug/kcov\n", th->id);
int kcov_mode = flag_collect_comps ? KCOV_TRACE_CMP : KCOV_TRACE_PC;
// This should be fatal,
@@ -169,17 +162,13 @@ void cover_enable(thread_t* th)
void cover_reset(thread_t* th)
{
- if (!flag_cover)
- return;
if (th == 0)
th = current_thread;
*(uint64*)th->cover_data = 0;
}
-uint32 read_cover_size(thread_t* th)
+uint32 cover_read_size(thread_t* th)
{
- if (!flag_cover)
- return 0;
// Note: this assumes little-endian kernel.
uint32 n = *(uint32*)th->cover_data;
debug("#%d: read cover size = %u\n", th->id, n);
diff --git a/executor/executor_windows.cc b/executor/executor_windows.cc
index a9ba5ea63..73477bb4f 100644
--- a/executor/executor_windows.cc
+++ b/executor/executor_windows.cc
@@ -27,8 +27,7 @@ int main(int argc, char** argv)
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) != (void*)SYZ_DATA_OFFSET)
fail("mmap of data segment failed");
- setup_control_pipes();
- receive_execute(true);
+ main_init();
execute_one();
return 0;
}
@@ -54,7 +53,7 @@ void cover_reset(thread_t* th)
{
}
-uint32 read_cover_size(thread_t* th)
+uint32 cover_read_size(thread_t* th)
{
return 0;
}
diff --git a/executor/syscalls_akaros.h b/executor/syscalls_akaros.h
index 6ea7ea44e..de24a539f 100644
--- a/executor/syscalls_akaros.h
+++ b/executor/syscalls_akaros.h
@@ -3,6 +3,8 @@
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "9c09d67e0d2fb4a004add22093616420ce831dfc"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_freebsd.h b/executor/syscalls_freebsd.h
index a8b960a31..d0d062e46 100644
--- a/executor/syscalls_freebsd.h
+++ b/executor/syscalls_freebsd.h
@@ -3,6 +3,8 @@
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "8cb11e146d49a5c6a0d12d988e21f2e9ca2c2f94"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_fuchsia.h b/executor/syscalls_fuchsia.h
index 71168ed25..63031eaa8 100644
--- a/executor/syscalls_fuchsia.h
+++ b/executor/syscalls_fuchsia.h
@@ -3,6 +3,8 @@
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "5c60584793306c995f51b459bc98d260d6af8fd2"
+#define SYZ_EXECUTOR_USES_FORK_SERVER false
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@@ -172,6 +174,8 @@ const call_t syscalls[] = {
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
#define SYZ_REVISION "2e963a82bfbf3c29beae3fc949984472c9ef3512"
+#define SYZ_EXECUTOR_USES_FORK_SERVER false
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_linux.h b/executor/syscalls_linux.h
index ef41c5885..5847f7412 100644
--- a/executor/syscalls_linux.h
+++ b/executor/syscalls_linux.h
@@ -3,6 +3,8 @@
#if defined(__i386__) || 0
#define GOARCH "386"
#define SYZ_REVISION "fb282f1b092787fbad00ac8e1b8c7b09fe9c4508"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@@ -2012,6 +2014,8 @@ const call_t syscalls[] = {
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "ebc5f87dbeb579da0b2fa1afa8b276abd3d76db7"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@@ -4073,6 +4077,8 @@ const call_t syscalls[] = {
#if defined(__arm__) || 0
#define GOARCH "arm"
#define SYZ_REVISION "feecafc9df92bb96d867216b25547470c3c5df58"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@@ -6090,6 +6096,8 @@ const call_t syscalls[] = {
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
#define SYZ_REVISION "2cb4965554b7542cf6dc6680a92afe835ce1734f"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@@ -8079,6 +8087,8 @@ const call_t syscalls[] = {
#if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0
#define GOARCH "ppc64le"
#define SYZ_REVISION "49784caa8d5d34e193d979e258ed6b6d04fbfe8a"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_netbsd.h b/executor/syscalls_netbsd.h
index a4cc3b867..9d2354f67 100644
--- a/executor/syscalls_netbsd.h
+++ b/executor/syscalls_netbsd.h
@@ -3,6 +3,8 @@
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "1c3f97d7ba7aa2f74ff155a040df838ef118c890"
+#define SYZ_EXECUTOR_USES_FORK_SERVER true
+#define SYZ_EXECUTOR_USES_SHMEM true
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_test.h b/executor/syscalls_test.h
index f1359a023..5a1c84410 100644
--- a/executor/syscalls_test.h
+++ b/executor/syscalls_test.h
@@ -3,6 +3,8 @@
#if 0
#define GOARCH "32"
#define SYZ_REVISION "d92d7712e00dad64bba08d7850d58c2c07fce4a2"
+#define SYZ_EXECUTOR_USES_FORK_SERVER false
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 8192
#define SYZ_NUM_PAGES 2048
#define SYZ_DATA_OFFSET 536870912
@@ -114,6 +116,8 @@ const call_t syscalls[] = {
#if 0
#define GOARCH "64"
#define SYZ_REVISION "043151c0569399dabddfd351e1e4e097cf457238"
+#define SYZ_EXECUTOR_USES_FORK_SERVER false
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/executor/syscalls_windows.h b/executor/syscalls_windows.h
index 1bb9af1b2..7dcf746a6 100644
--- a/executor/syscalls_windows.h
+++ b/executor/syscalls_windows.h
@@ -3,6 +3,8 @@
#if defined(_M_X64) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "6285e05d0c2a423477b78cca69c1143794a9b482"
+#define SYZ_EXECUTOR_USES_FORK_SERVER false
+#define SYZ_EXECUTOR_USES_SHMEM false
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go
index 8f293204f..d8dae4b22 100644
--- a/pkg/csource/linux_common.go
+++ b/pkg/csource/linux_common.go
@@ -2963,7 +2963,7 @@ extern unsigned long long procid;
#if defined(SYZ_EXECUTOR)
void reply_handshake();
-void receive_execute(bool need_prog);
+void receive_execute();
void reply_execute(int status);
extern uint32* output_data;
extern uint32* output_pos;
@@ -3027,7 +3027,7 @@ static void loop()
}
#endif
#if defined(SYZ_EXECUTOR)
- receive_execute(false);
+ receive_execute();
#endif
int pid = fork();
if (pid < 0)
diff --git a/pkg/host/host_freebsd.go b/pkg/host/host_freebsd.go
index 238edd46d..1d01cf743 100644
--- a/pkg/host/host_freebsd.go
+++ b/pkg/host/host_freebsd.go
@@ -10,7 +10,3 @@ import (
func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
return true, ""
}
-
-func init() {
- checkFeature[FeatureCoverage] = unconditionallyEnabled
-}
diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go
index 5619f16de..871401164 100644
--- a/pkg/ipc/ipc.go
+++ b/pkg/ipc/ipc.go
@@ -157,8 +157,9 @@ func DefaultConfig() (*Config, *ExecOpts, error) {
}
type CallInfo struct {
- Signal []uint32 // feedback signal, filled if FlagSignal is set
- Cover []uint32 // per-call coverage, filled if FlagSignal is set and cover == true,
+ Executed bool
+ Signal []uint32 // feedback signal, filled if FlagSignal is set
+ Cover []uint32 // per-call coverage, filled if FlagSignal is set and cover == true,
//if dedup == false, then cov effectively contains a trace, otherwise duplicates are removed
Comps prog.CompMap // per-call comparison operands
Errno int // call errno (0 if the call was successful)
@@ -310,10 +311,26 @@ func (env *Env) Exec(opts *ExecOpts, p *prog.Prog) (output []byte, info []CallIn
if env.out != nil {
info, err0 = env.readOutCoverage(p)
+ if info != nil {
+ addFallbackSignal(p, info)
+ }
}
return
}
+// addFallbackSignal computes simple fallback signal in cases we don't have real coverage signal.
+// We use syscall number or-ed with returned errno value as signal.
+// At least this gives us all combinations of syscall+errno.
+func addFallbackSignal(p *prog.Prog, info []CallInfo) {
+ for i, call := range p.Calls {
+ inf := &info[i]
+ if !inf.Executed || len(inf.Signal) != 0 {
+ continue
+ }
+ inf.Signal = []uint32{uint32(call.Meta.ID)<<16 | uint32(inf.Errno)&0x3ff}
+ }
+}
+
func (env *Env) readOutCoverage(p *prog.Prog) (info []CallInfo, err0 error) {
out := ((*[1 << 28]uint32)(unsafe.Pointer(&env.out[0])))[:len(env.out)/int(unsafe.Sizeof(uint32(0)))]
readOut := func(v *uint32) bool {
@@ -377,6 +394,7 @@ func (env *Env) readOutCoverage(p *prog.Prog) (info []CallInfo, err0 error) {
return
}
c := p.Calls[callIndex]
+ info[callIndex].Executed = true
if num := c.Meta.ID; uint32(num) != callNum {
err0 = fmt.Errorf("executor %v: failed to read output coverage:"+
" record %v call %v: expect syscall %v, got %v, executed %v (cov: %v)",
diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go
index ea8525cbc..33dc535bf 100644
--- a/sys/syz-sysgen/sysgen.go
+++ b/sys/syz-sysgen/sysgen.go
@@ -176,6 +176,8 @@ func generateExecutorSyscalls(target *targets.Target, syscalls []*prog.Syscall,
}
type ArchData struct {
Revision string
+ ForkServer bool
+ Shmem bool
GOARCH string
CARCH []string
PageSize uint64
@@ -185,6 +187,8 @@ func generateExecutorSyscalls(target *targets.Target, syscalls []*prog.Syscall,
}
data := ArchData{
Revision: rev,
+ ForkServer: target.ExecutorUsesForkServer,
+ Shmem: target.ExecutorUsesShmem,
GOARCH: target.Arch,
CARCH: target.CArch,
PageSize: target.PageSize,
@@ -248,6 +252,8 @@ var archTempl = template.Must(template.New("").Parse(`
#if {{range $cdef := $.CARCH}}defined({{$cdef}}) || {{end}}0
#define GOARCH "{{.GOARCH}}"
#define SYZ_REVISION "{{.Revision}}"
+#define SYZ_EXECUTOR_USES_FORK_SERVER {{.ForkServer}}
+#define SYZ_EXECUTOR_USES_SHMEM {{.Shmem}}
#define SYZ_PAGE_SIZE {{.PageSize}}
#define SYZ_NUM_PAGES {{.NumPages}}
#define SYZ_DATA_OFFSET {{.DataOffset}}
diff --git a/sys/targets/targets.go b/sys/targets/targets.go
index 5c41d8e66..2325f17c3 100644
--- a/sys/targets/targets.go
+++ b/sys/targets/targets.go
@@ -231,7 +231,7 @@ var oses = map[string]osCommon{
SyscallNumbers: true,
SyscallPrefix: "SYS_",
ExecutorUsesShmem: false,
- ExecutorUsesForkServer: false,
+ ExecutorUsesForkServer: true,
},
}
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index 9681be7a8..5ba5e67d5 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -42,7 +42,6 @@ type Fuzzer struct {
faultInjectionEnabled bool
comparisonTracingEnabled bool
- coverageEnabled bool
corpusMu sync.RWMutex
corpus []*prog.Prog
@@ -206,7 +205,6 @@ func main() {
if r.CheckResult.Features[host.FeatureFaultInjection].Enabled {
config.Flags |= ipc.FlagEnableFault
}
- coverageEnabled := config.Flags&ipc.FlagSignal != 0
calls := make(map[*prog.Syscall]bool)
for _, id := range r.CheckResult.EnabledCalls {
calls[target.Syscalls[id]] = true
@@ -227,7 +225,6 @@ func main() {
target: target,
faultInjectionEnabled: r.CheckResult.Features[host.FeatureFaultInjection].Enabled,
comparisonTracingEnabled: r.CheckResult.Features[host.FeatureComparisons].Enabled,
- coverageEnabled: coverageEnabled,
corpusHashes: make(map[hash.Sig]struct{}),
}
fuzzer.gate = ipc.NewGate(2**flagProcs, periodicCallback)
@@ -241,21 +238,17 @@ func main() {
if err != nil {
log.Fatalf("failed to deserialize program: %v", err)
}
- if coverageEnabled {
- flags := ProgCandidate
- if candidate.Minimized {
- flags |= ProgMinimized
- }
- if candidate.Smashed {
- flags |= ProgSmashed
- }
- fuzzer.workQueue.enqueue(&WorkCandidate{
- p: p,
- flags: flags,
- })
- } else {
- fuzzer.addInputToCorpus(p, nil, hash.Hash(candidate.Prog))
+ flags := ProgCandidate
+ if candidate.Minimized {
+ flags |= ProgMinimized
+ }
+ if candidate.Smashed {
+ flags |= ProgSmashed
}
+ fuzzer.workQueue.enqueue(&WorkCandidate{
+ p: p,
+ flags: flags,
+ })
}
for pid := 0; pid < *flagProcs; pid++ {
@@ -326,21 +319,17 @@ func (fuzzer *Fuzzer) pollLoop() {
if err != nil {
log.Fatalf("failed to parse program from manager: %v", err)
}
- if fuzzer.coverageEnabled {
- flags := ProgCandidate
- if candidate.Minimized {
- flags |= ProgMinimized
- }
- if candidate.Smashed {
- flags |= ProgSmashed
- }
- fuzzer.workQueue.enqueue(&WorkCandidate{
- p: p,
- flags: flags,
- })
- } else {
- fuzzer.addInputToCorpus(p, nil, hash.Hash(candidate.Prog))
+ flags := ProgCandidate
+ if candidate.Minimized {
+ flags |= ProgMinimized
}
+ if candidate.Smashed {
+ flags |= ProgSmashed
+ }
+ fuzzer.workQueue.enqueue(&WorkCandidate{
+ p: p,
+ flags: flags,
+ })
}
if len(r.NewInputs) == 0 && len(r.Candidates) == 0 {
lastPoll = time.Now()
@@ -360,9 +349,6 @@ func (fuzzer *Fuzzer) sendInputToManager(inp rpctype.RPCInput) {
}
func (fuzzer *Fuzzer) addInputFromAnotherFuzzer(inp rpctype.RPCInput) {
- if !fuzzer.coverageEnabled {
- panic("should not be called when coverage is disabled")
- }
p, err := fuzzer.target.Deserialize(inp.Prog)
if err != nil {
panic(err)
diff --git a/syz-fuzzer/proc.go b/syz-fuzzer/proc.go
index 011668ae8..013b25beb 100644
--- a/syz-fuzzer/proc.go
+++ b/syz-fuzzer/proc.go
@@ -99,9 +99,6 @@ func (proc *Proc) loop() {
func (proc *Proc) triageInput(item *WorkTriage) {
log.Logf(1, "#%v: triaging type=%x", proc.pid, item.flags)
- if !proc.fuzzer.coverageEnabled {
- panic("should not be called when coverage is disabled")
- }
call := item.p.Calls[item.call]
inputSignal := signal.FromRaw(item.info.Signal, signalPrio(item.p.Target, call, &item.info))
diff --git a/syz-fuzzer/testing.go b/syz-fuzzer/testing.go
index e37975a23..5887c9bbc 100644
--- a/syz-fuzzer/testing.go
+++ b/syz-fuzzer/testing.go
@@ -128,11 +128,14 @@ func checkSimpleProgram(args *checkArgs) error {
return fmt.Errorf("no calls executed:\n%s", output)
}
if info[0].Errno != 0 {
- return fmt.Errorf("simple call failed: %v\n%s", info[0].Errno, output)
+ return fmt.Errorf("simple call failed: %+v\n%s", info[0], output)
}
- if args.ipcConfig.Flags&ipc.FlagSignal != 0 && len(info[0].Signal) == 0 {
+ if args.ipcConfig.Flags&ipc.FlagSignal != 0 && len(info[0].Signal) < 2 {
return fmt.Errorf("got no coverage:\n%s", output)
}
+ if len(info[0].Signal) < 1 {
+ return fmt.Errorf("got no fallback coverage:\n%s", output)
+ }
return nil
}
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index 964bc3e32..c99cd5e11 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -845,34 +845,36 @@ func (mgr *Manager) getReporter() report.Reporter {
}
func (mgr *Manager) minimizeCorpus() {
- if mgr.cfg.Cover && len(mgr.corpus) != 0 {
- inputs := make([]signal.Context, 0, len(mgr.corpus))
- for _, inp := range mgr.corpus {
- inputs = append(inputs, signal.Context{
- Signal: inp.Signal.Deserialize(),
- Context: inp,
- })
- }
- newCorpus := make(map[string]rpctype.RPCInput)
- for _, ctx := range signal.Minimize(inputs) {
- inp := ctx.(rpctype.RPCInput)
- newCorpus[hash.String(inp.Prog)] = inp
- }
- log.Logf(1, "minimized corpus: %v -> %v", len(mgr.corpus), len(newCorpus))
- mgr.corpus = newCorpus
+ if mgr.phase < phaseLoadedCorpus {
+ return
}
+ inputs := make([]signal.Context, 0, len(mgr.corpus))
+ for _, inp := range mgr.corpus {
+ inputs = append(inputs, signal.Context{
+ Signal: inp.Signal.Deserialize(),
+ Context: inp,
+ })
+ }
+ newCorpus := make(map[string]rpctype.RPCInput)
+ for _, ctx := range signal.Minimize(inputs) {
+ inp := ctx.(rpctype.RPCInput)
+ newCorpus[hash.String(inp.Prog)] = inp
+ }
+ log.Logf(1, "minimized corpus: %v -> %v", len(mgr.corpus), len(newCorpus))
+ mgr.corpus = newCorpus
// Don't minimize persistent corpus until fuzzers have triaged all inputs from it.
- if mgr.phase >= phaseTriagedCorpus {
- for key := range mgr.corpusDB.Records {
- _, ok1 := mgr.corpus[key]
- _, ok2 := mgr.disabledHashes[key]
- if !ok1 && !ok2 {
- mgr.corpusDB.Delete(key)
- }
+ if mgr.phase < phaseTriagedCorpus {
+ return
+ }
+ for key := range mgr.corpusDB.Records {
+ _, ok1 := mgr.corpus[key]
+ _, ok2 := mgr.disabledHashes[key]
+ if !ok1 && !ok2 {
+ mgr.corpusDB.Delete(key)
}
- mgr.corpusDB.BumpVersion(currentDBVersion)
}
+ mgr.corpusDB.BumpVersion(currentDBVersion)
}
func (mgr *Manager) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) error {
diff --git a/vm/gvisor/gvisor.go b/vm/gvisor/gvisor.go
index acd04a4e7..eaef58969 100644
--- a/vm/gvisor/gvisor.go
+++ b/vm/gvisor/gvisor.go
@@ -216,7 +216,7 @@ func (inst *instance) Copy(hostSrc string) (string, error) {
func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (
<-chan []byte, <-chan error, error) {
- args := []string{"exec"}
+ args := []string{"exec", "-user=0:0"}
for _, c := range sandboxCaps {
args = append(args, "-cap", c)
}