diff options
Diffstat (limited to 'executor/executor.cc')
| -rw-r--r-- | executor/executor.cc | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/executor/executor.cc b/executor/executor.cc index 02792f82f..bdda612ca 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -76,9 +76,14 @@ bool flag_collide; bool flag_sandbox_privs; sandbox_type flag_sandbox; bool flag_enable_tun; +bool flag_enable_fault_injection; bool flag_collect_cover; bool flag_dedup_cover; +// Inject fault into flag_fault_nth-th operation in flag_fault_call-th syscall. +bool flag_inject_fault; +int flag_fault_call; +int flag_fault_nth; __attribute__((aligned(64 << 10))) char input_data[kMaxInput]; uint32_t* output_data; @@ -111,6 +116,7 @@ struct thread_t { uint64_t res; uint64_t reserrno; uint64_t cover_size; + bool fault_injected; int cover_fd; }; @@ -135,7 +141,6 @@ void execute_call(thread_t* th); void handle_completion(thread_t* th); void thread_create(thread_t* th, int id); void* worker_thread(void* arg); -bool write_file(const char* file, const char* what, ...); void cover_open(); void cover_enable(thread_t* th); void cover_reset(thread_t* th); @@ -176,8 +181,9 @@ int main(int argc, char** argv) if (!flag_threaded) flag_collide = false; flag_enable_tun = flags & (1 << 6); - uint64_t executor_pid = *((uint64_t*)input_data + 1); + flag_enable_fault_injection = flags & (1 << 7); + uint64_t executor_pid = *((uint64_t*)input_data + 1); cover_open(); setup_main_process(); @@ -240,11 +246,16 @@ 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. - char flags = 0; - if (read(kInPipeFd, &flags, 1) != 1) + 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 = flags & (1 << 0); - flag_dedup_cover = flags & (1 << 1); + 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_fault_call = in_cmd[1]; + flag_fault_nth = in_cmd[2]; + debug("exec opts: cover=%d dedup=%d fault=%d/%d/%d\n", flag_collect_cover, flag_dedup_cover, + flag_inject_fault, flag_fault_call, flag_fault_nth); int pid = fork(); if (pid < 0) @@ -482,7 +493,7 @@ retry: } } - if (flag_collide && !collide) { + if (flag_collide && !flag_inject_fault && !collide) { debug("enabling collider\n"); collide = true; goto retry; @@ -561,6 +572,7 @@ void handle_completion(thread_t* th) write_output(th->call_num); uint32_t reserrno = th->res != (uint64_t)-1 ? 0 : th->reserrno; write_output(reserrno); + write_output(th->fault_injected); uint32_t* signal_count_pos = write_output(0); // filled in later uint32_t* cover_count_pos = write_output(0); // filled in later @@ -651,10 +663,39 @@ void execute_call(thread_t* th) } debug(")\n"); + int fail_fd = -1; + if (flag_inject_fault && th->call_index == flag_fault_call) { + if (collide) + fail("both collide and fault injection are enabled"); + debug("injecting fault into %d-th operation\n", flag_fault_nth); + char buf[128]; + sprintf(buf, "/proc/self/task/%d/fail-nth", (int)syscall(SYS_gettid)); + fail_fd = open(buf, O_RDWR); + if (fail_fd == -1) + fail("failed to open /proc/self/task/tid/fail-nth"); + sprintf(buf, "%d", flag_fault_nth + 1); + if (write(fail_fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) + fail("failed to write /proc/self/task/tid/fail-nth"); + } + cover_reset(th); th->res = execute_syscall(call->sys_nr, th->args[0], th->args[1], th->args[2], th->args[3], th->args[4], th->args[5], th->args[6], th->args[7], th->args[8]); th->reserrno = errno; th->cover_size = cover_read(th); + th->fault_injected = false; + + if (flag_inject_fault && th->call_index == flag_fault_call) { + char buf[16]; + int n = read(fail_fd, buf, sizeof(buf) - 1); + if (n <= 0) + fail("failed to read /proc/self/task/tid/fail-nth"); + th->fault_injected = n == 2 && buf[0] == '0' && buf[1] == '\n'; + buf[0] = '0'; + if (write(fail_fd, buf, 1) != 1) + fail("failed to write /proc/self/task/tid/fail-nth"); + close(fail_fd); + debug("fault injected: %d\n", th->fault_injected); + } if (th->res == (uint64_t)-1) debug("#%d: %s = errno(%ld)\n", th->id, call->name, th->reserrno); |
