aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h14
-rw-r--r--executor/common_akaros.h1
-rw-r--r--executor/common_freebsd.h1
-rw-r--r--executor/common_fuchsia.h1
-rw-r--r--executor/common_linux.h1
-rw-r--r--executor/common_windows.h2
-rw-r--r--executor/executor.h152
-rw-r--r--executor/executor_akaros.cc66
-rw-r--r--executor/executor_freebsd.cc29
-rw-r--r--executor/executor_fuchsia.cc29
-rw-r--r--executor/executor_linux.cc60
-rw-r--r--executor/executor_windows.cc29
12 files changed, 196 insertions, 189 deletions
diff --git a/executor/common.h b/executor/common.h
index 6cb7635f0..980ea74b7 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -23,8 +23,15 @@
#endif
#if defined(SYZ_EXECUTOR)
-#ifndef SYSCALLAPI
+#if defined(__GNUC__)
#define SYSCALLAPI
+#define NORETURN __attribute__((noreturn))
+#define ALIGNED(N) __attribute__((aligned(N)))
+#else
+// Assuming windows/cl.
+#define SYSCALLAPI WINAPI
+#define NORETURN __declspec(noreturn)
+#define ALIGNED(N) __declspec(align(N))
#endif
typedef long(SYSCALLAPI* syscall_t)(long, long, long, long, long, long, long, long, long);
@@ -58,7 +65,6 @@ const int kErrorStatus = 68;
NORETURN static void fail(const char* msg, ...)
{
int e = errno;
- fflush(stdout);
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
@@ -74,7 +80,6 @@ NORETURN static void fail(const char* msg, ...)
// kernel error (e.g. wrong syscall return value)
NORETURN static void error(const char* msg, ...)
{
- fflush(stdout);
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
@@ -84,12 +89,11 @@ NORETURN static void error(const char* msg, ...)
}
#endif
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT))
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR))
// just exit (e.g. due to temporal ENOMEM error)
NORETURN static void exitf(const char* msg, ...)
{
int e = errno;
- fflush(stdout);
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
diff --git a/executor/common_akaros.h b/executor/common_akaros.h
index 3a12bac0c..d37e05176 100644
--- a/executor/common_akaros.h
+++ b/executor/common_akaros.h
@@ -30,7 +30,6 @@
#endif
#define doexit exit
-#define NORETURN __attribute__((noreturn))
#include "common.h"
diff --git a/executor/common_freebsd.h b/executor/common_freebsd.h
index 87daa17ff..c072b12aa 100644
--- a/executor/common_freebsd.h
+++ b/executor/common_freebsd.h
@@ -19,7 +19,6 @@
#endif
#define doexit exit
-#define NORETURN __attribute__((noreturn))
#include "common.h"
diff --git a/executor/common_fuchsia.h b/executor/common_fuchsia.h
index 0403deafc..4dfad597d 100644
--- a/executor/common_fuchsia.h
+++ b/executor/common_fuchsia.h
@@ -21,7 +21,6 @@
#endif
#define doexit exit
-#define NORETURN __attribute__((noreturn))
#include "common.h"
diff --git a/executor/common_linux.h b/executor/common_linux.h
index df1262107..8b9c00bfd 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -127,7 +127,6 @@ __attribute__((noreturn)) static void doexit(int status)
for (i = 0;; i++) {
}
}
-#define NORETURN __attribute__((noreturn))
#endif
#if defined(SYZ_EXECUTOR)
diff --git a/executor/common_windows.h b/executor/common_windows.h
index dbc6b67c3..077bc874a 100644
--- a/executor/common_windows.h
+++ b/executor/common_windows.h
@@ -6,8 +6,6 @@
#include <windows.h>
#define doexit exit
-#define NORETURN
-#define SYSCALLAPI WINAPI
#include "common.h"
diff --git a/executor/executor.h b/executor/executor.h
index 94d3a2ca0..9e56f45e2 100644
--- a/executor/executor.h
+++ b/executor/executor.h
@@ -16,6 +16,19 @@
#define GIT_REVISION "unknown"
#endif
+#ifndef GOOS
+#define GOOS "unknown"
+#endif
+
+// Note: zircon max fd is 256.
+#ifndef DUP2_BROKEN
+const int kInPipeFd = 250; // remapped from stdin
+const int kOutPipeFd = 251; // remapped from stdout
+#else
+const int kInPipeFd = 0;
+const int kOutPipeFd = 1;
+#endif
+
const int kMaxInput = 2 << 20;
const int kMaxOutput = 16 << 20;
const int kMaxArgs = 9;
@@ -56,10 +69,15 @@ bool flag_inject_fault;
int flag_fault_call;
int flag_fault_nth;
+int flag_pid;
+
int running;
uint32_t completed;
bool collide;
+ALIGNED(64 << 10)
+char input_data[kMaxInput];
+
// We use the default value instead of results of failed syscalls.
// -1 is an invalid fd and an invalid address and deterministic,
// so good enough for our purposes.
@@ -106,6 +124,35 @@ struct res_t {
res_t results[kMaxCommands];
+const uint64_t kInMagic = 0xbadc0ffeebadface;
+const uint32_t kOutMagic = 0xbadf00d;
+
+struct handshake_req {
+ uint64_t magic;
+ uint64_t flags; // env flags
+ uint64_t pid;
+};
+
+struct handshake_reply {
+ uint32_t magic;
+};
+
+struct execute_req {
+ uint64_t magic;
+ uint64_t env_flags;
+ uint64_t exec_flags;
+ uint64_t pid;
+ uint64_t fault_call;
+ uint64_t fault_nth;
+ uint64_t prog_size;
+};
+
+struct execute_reply {
+ uint32_t magic;
+ uint32_t done;
+ uint32_t status;
+};
+
enum {
KCOV_CMP_CONST = 1,
KCOV_CMP_SIZE1 = 0,
@@ -148,10 +195,107 @@ uint64_t read_cover_size(thread_t* th);
static uint32_t hash(uint32_t a);
static bool dedup(uint32_t sig);
-void execute_one(uint64_t* input_data)
+void setup_control_pipes()
+{
+#ifndef DUP2_BROKEN
+ if (dup2(0, kInPipeFd) < 0)
+ fail("dup2(0, kInPipeFd) failed");
+ if (dup2(1, kOutPipeFd) < 0)
+ fail("dup2(1, kOutPipeFd) failed");
+ if (dup2(2, 1) < 0)
+ fail("dup2(2, 1) failed");
+ if (close(0))
+ fail("close(0) failed");
+#endif
+}
+
+void parse_env_flags(uint64_t flags)
+{
+ flag_debug = flags & (1 << 0);
+ flag_cover = flags & (1 << 1);
+ flag_threaded = flags & (1 << 2);
+ flag_collide = flags & (1 << 3);
+ flag_sandbox = sandbox_none;
+ if (flags & (1 << 4))
+ flag_sandbox = sandbox_setuid;
+ else if (flags & (1 << 5))
+ flag_sandbox = sandbox_namespace;
+ if (!flag_threaded)
+ flag_collide = false;
+ flag_enable_tun = flags & (1 << 6);
+ flag_enable_fault_injection = flags & (1 << 7);
+}
+
+void receive_handshake()
+{
+ handshake_req req = {};
+ int n = read(kInPipeFd, &req, sizeof(req));
+ if (n != sizeof(req))
+ fail("handshake read failed: %d", n);
+ if (req.magic != kInMagic)
+ fail("bad handshake magic 0x%llx", req.magic);
+ parse_env_flags(req.flags);
+ flag_pid = req.pid;
+}
+
+void reply_handshake()
+{
+ handshake_reply reply = {};
+ reply.magic = kOutMagic;
+ if (write(kOutPipeFd, &reply, sizeof(reply)) != sizeof(reply))
+ fail("control pipe write failed");
+}
+
+void receive_execute()
+{
+ execute_req req;
+ if (read(kInPipeFd, &req, sizeof(req)) != (ssize_t)sizeof(req))
+ fail("control pipe read failed");
+ if (req.magic != kInMagic)
+ fail("bad execute request magic 0x%llx", req.magic);
+ if (req.prog_size > kMaxInput)
+ fail("bad execute prog size 0x%llx", req.prog_size);
+ parse_env_flags(req.env_flags);
+ flag_pid = req.pid;
+ flag_collect_cover = req.exec_flags & (1 << 0);
+ flag_dedup_cover = req.exec_flags & (1 << 1);
+ flag_inject_fault = req.exec_flags & (1 << 2);
+ flag_collect_comps = req.exec_flags & (1 << 3);
+ flag_fault_call = req.fault_call;
+ flag_fault_nth = req.fault_nth;
+ debug("exec opts: cover=%d comps=%d dedup=%d fault=%d/%d/%d\n",
+ flag_collect_cover, flag_collect_comps, flag_dedup_cover,
+ flag_inject_fault, flag_fault_call, flag_fault_nth);
+ if (req.prog_size == 0)
+ return;
+ uint64_t pos = 0;
+ for (;;) {
+ ssize_t rv = read(kInPipeFd, input_data + pos, sizeof(input_data) - pos);
+ if (rv < 0)
+ fail("read failed");
+ pos += rv;
+ if (rv == 0 || pos >= req.prog_size)
+ break;
+ }
+ if (pos != req.prog_size)
+ fail("bad input size %d, want %d", pos, req.prog_size);
+}
+
+void reply_execute(int status)
+{
+ execute_reply reply = {};
+ reply.magic = kOutMagic;
+ reply.done = true;
+ reply.status = status;
+ if (write(kOutPipeFd, &reply, sizeof(reply)) != sizeof(reply))
+ fail("control pipe write failed");
+}
+
+// execute_one executes program stored in input_data.
+void execute_one()
{
retry:
- uint64_t* input_pos = input_data;
+ uint64_t* input_pos = (uint64_t*)input_data;
write_output(0); // Number of executed syscalls (updated later).
if (!collide && !flag_threaded)
@@ -611,8 +755,8 @@ uint64_t read_result(uint64_t** input_posp)
uint64_t read_input(uint64_t** input_posp, bool peek)
{
uint64_t* input_pos = *input_posp;
- //if ((char*)input_pos >= input_data + kMaxInput)
- // fail("input command overflows input");
+ if ((char*)input_pos >= input_data + kMaxInput)
+ fail("input command overflows input");
if (!peek)
*input_posp = input_pos + 1;
return *input_pos;
diff --git a/executor/executor_akaros.cc b/executor/executor_akaros.cc
index 15eafba71..e7d828a40 100644
--- a/executor/executor_akaros.cc
+++ b/executor/executor_akaros.cc
@@ -3,6 +3,9 @@
// +build
+// https://github.com/brho/akaros/issues/41
+#define DUP2_BROKEN
+
#define SYZ_EXECUTOR
#include "common_akaros.h"
@@ -12,83 +15,42 @@
#include "syscalls_akaros.h"
-char input_buffer[kMaxInput];
uint32_t output;
-struct in_header {
- uint64_t magic;
- uint64_t flags;
- uint64_t pid;
- uint64_t progSize;
- uint64_t execFlags;
- uint64_t prog[0];
-};
-
-struct out_header {
- uint64_t magic;
- uint64_t status;
-};
-
-const uint64_t kInMagic = 0xbadc0ffee;
-const uint64_t kOutMagic = 0xbadf00d;
-
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
- puts("akaros " GOARCH " " SYZ_REVISION " " GIT_REVISION);
+ puts(GOOS " " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
use_temporary_dir();
install_segv_handler();
+ setup_control_pipes();
+ receive_handshake();
+ reply_handshake();
+
for (;;) {
- size_t pos = 0;
- in_header* hdr = (in_header*)input_buffer;
- for (;;) {
- int rv = read(0, input_buffer + pos, sizeof(input_buffer) - pos);
- if (rv < 0)
- fail("read failed");
- if (rv == 0)
- fail("stdin closed, read %d", (int)pos);
- pos += rv;
- if (pos > sizeof(in_header)) {
- if (hdr->magic != kInMagic)
- fail("bad header magic 0x%llx", hdr->magic);
- if (pos > sizeof(in_header) + hdr->progSize)
- fail("excessive input data");
- if (pos == sizeof(in_header) + hdr->progSize)
- break;
- }
- }
- flag_debug = hdr->flags & (1 << 0);
- flag_threaded = hdr->flags & (1 << 2);
- flag_collide = hdr->flags & (1 << 3);
- if (!flag_threaded)
- flag_collide = false;
- debug("input %d, threaded=%d collide=%d pid=%llu\n",
- pos, flag_threaded, flag_collide, hdr->pid);
+ receive_execute();
char cwdbuf[128] = "/syz-tmpXXXXXX";
mkdtemp(cwdbuf);
int pid = fork();
if (pid < 0)
fail("fork failed");
if (pid == 0) {
- close(0);
- dup2(2, 1);
+ close(kInPipeFd);
+ close(kOutPipeFd);
if (chdir(cwdbuf))
fail("chdir failed");
- execute_one(hdr->prog);
+ execute_one();
doexit(0);
}
+ // TODO: timeout.
int status = 0;
while (waitpid(pid, &status, 0) != pid) {
}
remove_dir(cwdbuf);
- out_header out;
- out.magic = kOutMagic;
- out.status = 0;
- if (write(1, &out, sizeof(out)) != sizeof(out))
- fail("stdout write failed");
+ reply_execute(0);
}
return 0;
}
diff --git a/executor/executor_freebsd.cc b/executor/executor_freebsd.cc
index 8435d4465..abfb4139b 100644
--- a/executor/executor_freebsd.cc
+++ b/executor/executor_freebsd.cc
@@ -16,13 +16,12 @@
#include <sys/time.h>
#include <sys/types.h>
-char input_data[kMaxInput];
uint32_t output;
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
- puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION);
+ puts(GOOS " " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
@@ -40,29 +39,9 @@ int main(int argc, char** argv)
setrlimit(RLIMIT_CORE, &rlim);
install_segv_handler();
- int pos = 0;
- for (;;) {
- int rv = read(0, input_data + pos, sizeof(input_data) - pos);
- if (rv < 0)
- fail("read failed");
- if (rv == 0)
- break;
- pos += rv;
- }
- if (pos < 24)
- fail("truncated input");
-
- uint64_t flags = *(uint64_t*)input_data;
- flag_debug = flags & (1 << 0);
- flag_threaded = flags & (1 << 2);
- flag_collide = flags & (1 << 3);
- if (!flag_threaded)
- flag_collide = false;
- uint64_t executor_pid = *((uint64_t*)input_data + 2);
- debug("input %d, threaded=%d collide=%d pid=%llu\n",
- pos, flag_threaded, flag_collide, executor_pid);
-
- execute_one(((uint64_t*)input_data) + 3);
+ setup_control_pipes();
+ receive_execute();
+ execute_one();
return 0;
}
diff --git a/executor/executor_fuchsia.cc b/executor/executor_fuchsia.cc
index a5aa19470..dd9204d7d 100644
--- a/executor/executor_fuchsia.cc
+++ b/executor/executor_fuchsia.cc
@@ -12,40 +12,19 @@
#include "syscalls_fuchsia.h"
-char input_data[kMaxInput];
uint32_t output;
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
- puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION);
+ puts(GOOS " " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
install_segv_handler();
- int pos = 0;
- for (;;) {
- int rv = read(0, input_data + pos, sizeof(input_data) - pos);
- if (rv < 0)
- fail("read failed");
- if (rv == 0)
- break;
- pos += rv;
- }
- if (pos < 24)
- fail("truncated input");
-
- uint64_t flags = *(uint64_t*)input_data;
- flag_debug = flags & (1 << 0);
- flag_threaded = flags & (1 << 2);
- flag_collide = flags & (1 << 3);
- if (!flag_threaded)
- flag_collide = false;
- uint64_t executor_pid = *((uint64_t*)input_data + 2);
- debug("input %d, threaded=%d collide=%d pid=%llu\n",
- pos, flag_threaded, flag_collide, executor_pid);
-
- execute_one(((uint64_t*)input_data) + 3);
+ setup_control_pipes();
+ receive_execute();
+ execute_one();
return 0;
}
diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc
index 7a26d71c0..72bd91aa8 100644
--- a/executor/executor_linux.cc
+++ b/executor/executor_linux.cc
@@ -34,19 +34,16 @@ const unsigned long KCOV_TRACE_CMP = 1;
const int kInFd = 3;
const int kOutFd = 4;
-const int kInPipeFd = 5;
-const int kOutPipeFd = 6;
const int kCoverSize = 64 << 10;
const int kPageSize = 4 << 10;
-__attribute__((aligned(64 << 10))) char input_data[kMaxInput];
uint32_t* output_data;
uint32_t* output_pos;
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
- puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION);
+ puts(GOOS " " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
@@ -67,23 +64,9 @@ 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();
- uint64_t flags = *(uint64_t*)input_data;
- flag_debug = flags & (1 << 0);
- flag_cover = flags & (1 << 1);
- flag_threaded = flags & (1 << 2);
- flag_collide = flags & (1 << 3);
- flag_sandbox = sandbox_none;
- if (flags & (1 << 4))
- flag_sandbox = sandbox_setuid;
- else if (flags & (1 << 5))
- flag_sandbox = sandbox_namespace;
- if (!flag_threaded)
- flag_collide = false;
- flag_enable_tun = flags & (1 << 6);
- flag_enable_fault_injection = flags & (1 << 7);
-
- uint64_t executor_pid = *((uint64_t*)input_data + 1);
cover_open();
install_segv_handler();
use_temporary_dir();
@@ -101,13 +84,13 @@ int main(int argc, char** argv)
int pid = -1;
switch (flag_sandbox) {
case sandbox_none:
- pid = do_sandbox_none(executor_pid, flag_enable_tun);
+ pid = do_sandbox_none(flag_pid, flag_enable_tun);
break;
case sandbox_setuid:
- pid = do_sandbox_setuid(executor_pid, flag_enable_tun);
+ pid = do_sandbox_setuid(flag_pid, flag_enable_tun);
break;
case sandbox_namespace:
- pid = do_sandbox_namespace(executor_pid, flag_enable_tun);
+ pid = do_sandbox_namespace(flag_pid, flag_enable_tun);
break;
default:
fail("unknown sandbox type");
@@ -119,15 +102,14 @@ int main(int argc, char** argv)
while (waitpid(-1, &status, __WALL) != pid) {
}
status = WEXITSTATUS(status);
+ if (status == 0)
+ status = kRetryStatus;
// If an external sandbox process wraps executor, the out pipe will be closed
// before the sandbox process exits this will make ipc package kill the sandbox.
// As the result sandbox process will exit with exit status 9 instead of the executor
// exit status (notably kRetryStatus). Consequently, ipc will treat it as hard
// failure rather than a temporal failure. So we duplicate the exit status on the pipe.
- char tmp = status;
- if (write(kOutPipeFd, &tmp, 1)) {
- // Not much we can do, but gcc wants us to check the return value.
- }
+ reply_execute(status);
errno = 0;
if (status == kFailStatus)
fail("loop failed");
@@ -144,9 +126,7 @@ int main(int argc, char** argv)
void loop()
{
// Tell parent that we are ready to serve.
- char tmp = 0;
- if (write(kOutPipeFd, &tmp, 1) != 1)
- fail("control pipe write failed");
+ reply_handshake();
for (int iter = 0;; iter++) {
// Create a new private work dir for this test (removed at the end of the loop).
@@ -158,19 +138,7 @@ 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.
- uint64_t in_cmd[3] = {};
- if (read(kInPipeFd, &in_cmd[0], sizeof(in_cmd)) != (ssize_t)sizeof(in_cmd))
- fail("control pipe read failed");
- flag_collect_cover = in_cmd[0] & (1 << 0);
- flag_dedup_cover = in_cmd[0] & (1 << 1);
- flag_inject_fault = in_cmd[0] & (1 << 2);
- flag_collect_comps = in_cmd[0] & (1 << 3);
- flag_fault_call = in_cmd[1];
- flag_fault_nth = in_cmd[2];
- debug("exec opts: cover=%d comps=%d dedup=%d fault=%d/%d/%d\n", flag_collect_cover,
- flag_collect_comps, flag_dedup_cover,
- flag_inject_fault, flag_fault_call, flag_fault_nth);
-
+ receive_execute();
int pid = fork();
if (pid < 0)
fail("clone failed");
@@ -186,9 +154,8 @@ void loop()
// isolate consequently executing programs.
flush_tun();
}
- uint64_t* input_pos = ((uint64_t*)&input_data[0]) + 2; // skip flags and pid
output_pos = output_data;
- execute_one(input_pos);
+ execute_one();
debug("worker exiting\n");
doexit(0);
}
@@ -247,8 +214,7 @@ void loop()
if (status == kErrorStatus)
error("child errored");
remove_dir(cwdbuf);
- if (write(kOutPipeFd, &tmp, 1) != 1)
- fail("control pipe write failed");
+ reply_execute(0);
}
}
diff --git a/executor/executor_windows.cc b/executor/executor_windows.cc
index 862621951..0124aa0d9 100644
--- a/executor/executor_windows.cc
+++ b/executor/executor_windows.cc
@@ -14,39 +14,18 @@
#include "syscalls_windows.h"
-char input_data[kMaxInput];
uint32_t output;
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
- puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION);
+ puts(GOOS " " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
- int pos = 0;
- for (;;) {
- int rv = _read(0, input_data + pos, sizeof(input_data) - pos);
- if (rv < 0)
- fail("read failed");
- if (rv == 0)
- break;
- pos += rv;
- }
- if (pos < 24)
- fail("truncated input");
-
- uint64_t flags = *(uint64_t*)input_data;
- flag_debug = flags & (1 << 0);
- flag_threaded = flags & (1 << 2);
- flag_collide = flags & (1 << 3);
- if (!flag_threaded)
- flag_collide = false;
- uint64_t executor_pid = *((uint64_t*)input_data + 2);
- debug("input %d, threaded=%d collide=%d pid=%llu\n",
- pos, flag_threaded, flag_collide, executor_pid);
-
- execute_one(((uint64_t*)input_data) + 3);
+ setup_control_pipes();
+ receive_execute();
+ execute_one();
return 0;
}