about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRishi Ranjan <43873720+rish9101@users.noreply.github.com>2020-03-11 05:04:51 +0530
committerGitHub <noreply@github.com>2020-03-11 00:34:51 +0100
commitf17a3dde1a57ff631f691abca7cdcad99cb6631f (patch)
tree72c94709e41544e5af8fc1e05e4a6154572643de
parent88ced831c14a6d6c6634630bcdd7c692085718c3 (diff)
downloadafl++-f17a3dde1a57ff631f691abca7cdcad99cb6631f.tar.gz
Replace timer with select in forkserver, where possible (#246)
-rw-r--r--src/afl-fuzz-run.c189
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] == '.' ||