diff options
author | Rishi Ranjan <43873720+rish9101@users.noreply.github.com> | 2020-03-11 05:04:51 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-11 00:34:51 +0100 |
commit | f17a3dde1a57ff631f691abca7cdcad99cb6631f (patch) | |
tree | 72c94709e41544e5af8fc1e05e4a6154572643de | |
parent | 88ced831c14a6d6c6634630bcdd7c692085718c3 (diff) | |
download | afl++-f17a3dde1a57ff631f691abca7cdcad99cb6631f.tar.gz |
Replace timer with select in forkserver, where possible (#246)
-rw-r--r-- | src/afl-fuzz-run.c | 189 |
1 files changed, 104 insertions, 85 deletions
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 527782e4..fa28a4ab 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -39,10 +39,10 @@ void timeout_handle(union sigval timer_data) { u8 run_target(afl_state_t *afl, u32 timeout) { - // static struct itimerval it; struct sigevent timer_signal_event; static timer_t timer; static struct itimerspec timer_period; + static struct timeval it; static u32 prev_timed_out = 0; static u64 exec_ms = 0; @@ -151,62 +151,61 @@ u8 run_target(afl_state_t *afl, u32 timeout) { } - } else { + /* Configure timeout using POSIX timers in dumb-mode, + as requested by user, then wait for child to terminate. + */ - s32 res; + timer_signal_event.sigev_value.sival_int = afl->fsrv.child_pid; + timer_status = timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer); - /* In non-dumb mode, we have the fork server up and running, so simply - tell it to have at it, and then read back PID. */ + if (timer_status == -1) { FATAL("Failed to create Timer"); } - if ((res = write(afl->fsrv.fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { + timer_period.it_value.tv_sec = (timeout / 1000); + timer_period.it_value.tv_nsec = (timeout % 1000) * 1000000; + timer_period.it_interval.tv_sec = 0; + timer_period.it_interval.tv_nsec = 0; - if (afl->stop_soon) goto handle_stop_soon; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + timer_status = timer_settime(timer, 0, &timer_period, NULL); - } + if (timer_status == -1) { - if ((res = read(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) { + timer_delete(timer); + if (errno == EINVAL) { - if (afl->stop_soon) goto handle_stop_soon; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + FATAL("Failed to set the timer. The timeout given is invalid."); - } + } else { - if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); + FATAL("Failed to set the timer to the given timeout"); - } + } - /* Configure timeout, as requested by user, then wait for child to terminate. - */ - timer_signal_event.sigev_value.sival_int = afl->fsrv.child_pid; - timer_status = timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer); + } - if (timer_status == -1) { FATAL("Failed to create Timer"); } + } else { - timer_period.it_value.tv_sec = (timeout / 1000); - timer_period.it_value.tv_nsec = (timeout % 1000) * 1000000; - timer_period.it_interval.tv_sec = 0; - timer_period.it_interval.tv_nsec = 0; + /* In non-dumb mode, we have the fork server up and running, so simply + tell it to have at it, and then read back PID. */ - timer_status = timer_settime(timer, 0, &timer_period, NULL); + int res; - if (timer_status == -1) { + if ((res = write(afl->fsrv.fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { - timer_delete(timer); - if (errno == EINVAL) { + if (afl->stop_soon) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - FATAL("Failed to set the timer. The timeout given is invalid."); + } - } else { + if ((res = read(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) { - FATAL("Failed to set the timer to the given timeout"); + if (afl->stop_soon) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); } - } + if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - /* The SIGALRM handler simply kills the afl->fsrv.child_pid and sets - * afl->fsrv.child_timed_out. */ + } if (afl->dumb_mode == 1 || afl->no_forkserver) { @@ -217,61 +216,85 @@ u8 run_target(afl_state_t *afl, u32 timeout) { } - } else { + timer_gettime(timer, &timer_period); + exec_ms = (u64)timeout - (timer_period.it_value.tv_sec * 1000 + + timer_period.it_value.tv_nsec / 1000000); + timer_period.it_value.tv_sec = 0; + timer_period.it_value.tv_nsec = 0; - s32 res; + timer_status = timer_settime(timer, 0, &timer_period, NULL); + + if (timer_status == -1) { - if ((res = read(afl->fsrv.fsrv_st_fd, &status, 4)) != 4) { - - if (afl->stop_soon) goto handle_stop_soon; - SAYF( - "\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n" - " - If using persistent mode with QEMU, AFL_QEMU_PERSISTENT_ADDR " - "is\n" - " probably not valid (hint: add the base address in case of PIE)" - "\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); timer_delete(timer); - RPFATAL(res, "Unable to communicate with fork server"); + FATAL("Failed to reset the timer."); } - } + timer_delete(timer); - if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0; + } else { - timer_gettime(timer, &timer_period); - exec_ms = (u64)timeout - (timer_period.it_value.tv_sec * 1000 + - timer_period.it_value.tv_nsec / 1000000); - if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; + /* In non-dumb mode, use select to monitor the forkserver for timeouts. + */ - if (exec_ms >= timeout) { afl->fsrv.child_timed_out = 1; } + s32 res; + int sret; - timer_period.it_value.tv_sec = 0; - timer_period.it_value.tv_nsec = 0; + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(afl->fsrv.fsrv_st_fd, &readfds); + it.tv_sec = ((timeout) / 1000); + it.tv_usec = ((timeout) % 1000) * 1000; - timer_status = timer_settime(timer, 0, &timer_period, NULL); + sret = select(afl->fsrv.fsrv_st_fd + 1, &readfds, NULL, NULL, &it); - if (timer_status == -1) { + if (sret == 0) { - timer_delete(timer); - FATAL("Failed to reset the timer."); + kill(afl->fsrv.child_pid, SIGKILL); + + } else { + + if ((res = read(afl->fsrv.fsrv_st_fd, &status, 4)) != 4) { + + if (afl->stop_soon) return 0; + SAYF( + "\n" cLRD "[-] " cRST + "Unable to communicate with fork server. Some possible reasons:\n\n" + " - You've run out of memory. Use -m to increase the the memory " + "limit\n" + " to something higher than %lld.\n" + " - The binary or one of the libraries it uses manages to " + "create\n" + " threads before the forkserver initializes.\n" + " - The binary, at least in some circumstances, exits in a way " + "that\n" + " also kills the parent process - raise() could be the " + "culprit.\n" + " - If using persistent mode with QEMU, " + "AFL_QEMU_PERSISTENT_ADDR " + "is\n" + " probably not valid (hint: add the base address in case of " + "PIE)" + "\n\n" + "If all else fails you can disable the fork server via " + "AFL_NO_FORKSRV=1.\n", + afl->fsrv.mem_limit); + RPFATAL(res, "Unable to communicate with fork server"); + + } + + } + + exec_ms = (u64)timeout - (it.tv_sec * 1000 + it.tv_usec / 1000); + it.tv_sec = 0; + it.tv_usec = 0; } - timer_delete(timer); + if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0; + + if (exec_ms >= timeout) { afl->fsrv.child_timed_out = 1; } ++afl->total_execs; @@ -319,10 +342,6 @@ u8 run_target(afl_state_t *afl, u32 timeout) { return FAULT_NONE; -handle_stop_soon: - timer_delete(timer); - return 0; - } /* Write modified data to file for testing. If afl->fsrv.out_file is set, the @@ -374,7 +393,7 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { if (afl->mutator && afl->mutator->afl_custom_pre_save) { - u8 *new_data; + u8 * new_data; size_t new_size = afl->mutator->afl_custom_pre_save(afl, mem, len, &new_data); ck_write(fd, new_data, new_size, afl->fsrv.out_file); @@ -606,9 +625,9 @@ abort_calibration: void sync_fuzzers(afl_state_t *afl) { - DIR *sd; + DIR * sd; struct dirent *sd_ent; - u32 sync_cnt = 0; + u32 sync_cnt = 0; sd = opendir(afl->sync_dir); if (!sd) PFATAL("Unable to open '%s'", afl->sync_dir); @@ -623,10 +642,10 @@ void sync_fuzzers(afl_state_t *afl) { static u8 stage_tmp[128]; - DIR *qd; + DIR * qd; struct dirent *qd_ent; - u8 *qd_path, *qd_synced_path; - u32 min_accept = 0, next_min_accept; + u8 * qd_path, *qd_synced_path; + u32 min_accept = 0, next_min_accept; s32 id_fd; @@ -671,8 +690,8 @@ void sync_fuzzers(afl_state_t *afl) { while ((qd_ent = readdir(qd))) { - u8 *path; - s32 fd; + u8 * path; + s32 fd; struct stat st; if (qd_ent->d_name[0] == '.' || |