aboutsummaryrefslogtreecommitdiffstats
path: root/executor/executor.h
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-10-16 12:18:50 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-10-16 14:21:54 +0200
commit85b1f93f8dbbc767c564e494a6353aa3517d5d49 (patch)
tree702d2318a2ddcf1a576294a6a4981c58abcfcf61 /executor/executor.h
parentf78642861b4dbe396a67d5e2a750e22f83f3edd5 (diff)
executor, pkg/ipc: unify ipc protocol between linux and other OSes
We currently use more complex and functional protocol on linux, and a simple ad-hoc protocol on other OSes. This leads to code duplication in both ipc and executor. Linux supports coverage, shared memory communication and fork server, which would also be useful for most other OSes. Unify communication protocol and parametrize it by (1) use of shmem or only pipes, (2) use of fork server. This reduces duplication in ipc and executor and will allow to support the useful features for other OSes easily. Finally, this fixes akaros support as it currently uses syz-stress running on host (linux) and executor running on akaros.
Diffstat (limited to 'executor/executor.h')
-rw-r--r--executor/executor.h152
1 files changed, 148 insertions, 4 deletions
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;