about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDominik Maier <domenukk@gmail.com>2020-03-30 00:50:04 +0200
committerDominik Maier <domenukk@gmail.com>2020-04-01 13:10:06 +0200
commit452067ffca0de664fa4a11211c54f34c3842f20e (patch)
tree5796aa0fb75091579be89ac48fe364b553e31555
parent3ce5efc44b9d3e41d2928553fee2e51681c955d2 (diff)
downloadafl++-452067ffca0de664fa4a11211c54f34c3842f20e.tar.gz
added read_timed
-rw-r--r--docs/Changelog.md6
-rw-r--r--include/common.h50
-rw-r--r--include/types.h18
-rw-r--r--src/afl-forkserver.c24
-rw-r--r--src/afl-fuzz-cmplog.c67
-rw-r--r--src/afl-fuzz-redqueen.c5
-rw-r--r--src/afl-fuzz-run.c23
7 files changed, 112 insertions, 81 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 198909d1..407a3324 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -16,12 +16,14 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
   ! development and acceptance of PRs now happen only in the dev branch
     and only occasionally when everything is fine we PR to master
   - all:
-    - big code changes to make afl-fuzz thread-safe so afl-fuzz can spawn 
+    - big code changes to make afl-fuzz thread-safe so afl-fuzz can spawn
       multiple fuzzing threads in the future or even become a library
     - afl basic tools now report on the environment variables picked up
     - more tools get environment variable usage info in the help output
     - force all output to stdout (some OK/SAY/WARN messages were sent to
       stdout, some to stderr)
+    - uninstrumented mode uses an internal forkserver ("fauxserver")
+    - reduced number of (de)allocations
   - afl-fuzz:
     - python mutator modules and custom mutator modules now use the same
       interface and hence the API changed
@@ -38,7 +40,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     (https://github.com/adrianherrera/afl-ngram-pass/), activate by setting
     AFL_LLVM_NGRAM_SIZE
   - llvm_mode InsTrim mode:
-    - removed workaround for bug where paths were not instrumented and 
+    - removed workaround for bug where paths were not instrumented and
       imported fix by author
     - made skipping 1 block functions an option and is disable by default,
       set AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 to re-enable this
diff --git a/include/common.h b/include/common.h
index 8b21b55f..e8558e24 100644
--- a/include/common.h
+++ b/include/common.h
@@ -29,6 +29,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/time.h>
 #include "types.h"
 #include "stdbool.h"
@@ -390,5 +391,54 @@ static u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
 
 }
 
+/* Wrapper for select() and read(), reading exactly len bytes.
+  Returns the time passed to read.
+  If the wait times out, returns timeout_ms + 1;
+  Returns 0 if an error occurred (fd closed, signal, ...); */
+static inline u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
+
+  struct timeval timeout;
+  fd_set         readfds;
+  FD_ZERO(&readfds);
+  FD_SET(fd, &readfds);
+
+  timeout.tv_sec = (timeout_ms / 1000);
+  timeout.tv_usec = (timeout_ms % 1000) * 1000;
+
+  size_t read_total = 0;
+  size_t len_read = 0;
+
+  while (len_read < len) {
+
+    /* set exceptfds as well to return when a child exited/closed the pipe. */
+    int sret = select(fd + 1, &readfds, NULL, NULL, &timeout);
+
+    if (!sret) {
+
+      // printf("Timeout in sret.");
+      return timeout_ms + 1;
+
+    } else if (sret < 0) {
+
+      // perror("sret malloc");
+      // TODO: catch other (errno == EINTR) than ctrl+c?
+      return 0;
+
+    }
+
+    len_read = read(fd, buf + len_read, len - len_read);
+    if (!len_read) { return 0; }
+    read_total += len_read;
+
+  }
+
+  s32 exec_ms =
+      MIN(timeout_ms,
+          ((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000)));
+  return exec_ms > 0 ? exec_ms
+                     : 1;  // at least 1 milli must have passed (0 is an error)
+
+}
+
 #endif
 
diff --git a/include/types.h b/include/types.h
index ebc561f7..da95cb39 100644
--- a/include/types.h
+++ b/include/types.h
@@ -58,8 +58,22 @@ typedef int32_t s32;
 typedef int64_t s64;
 
 #ifndef MIN
-#define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a))
-#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
+#define MIN(a, b)           \
+  ({                        \
+                            \
+    __typeof__(a) _a = (a); \
+    __typeof__(b) _b = (b); \
+    _a < _b ? _a : _b;      \
+                            \
+  })
+#define MAX(a, b)           \
+  ({                        \
+                            \
+    __typeof__(a) _a = (a); \
+    __typeof__(b) _b = (b); \
+    _a > _b ? _a : _b;      \
+                            \
+  })
 #endif                                                              /* !MIN */
 
 #define SWAP16(_x)                    \
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 2dd7a9f0..01a606c3 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -164,10 +164,9 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
 
 void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
 
-  struct timeval timeout;
-  int            st_pipe[2], ctl_pipe[2];
-  int            status;
-  s32            rlen;
+  int st_pipe[2], ctl_pipe[2];
+  int status;
+  s32 rlen;
 
   if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:");
 
@@ -318,24 +317,15 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
   rlen = 0;
   if (fsrv->exec_tmout) {
 
-    fd_set readfds;
+    rlen = 4;
+    u32 time = read_timed(fsrv->fsrv_st_fd, &status, rlen,
+                          fsrv->exec_tmout * FORK_WAIT_MULT);
 
-    FD_ZERO(&readfds);
-    FD_SET(fsrv->fsrv_st_fd, &readfds);
-    timeout.tv_sec = ((fsrv->exec_tmout * FORK_WAIT_MULT) / 1000);
-    timeout.tv_usec = ((fsrv->exec_tmout * FORK_WAIT_MULT) % 1000) * 1000;
-
-    int sret = select(fsrv->fsrv_st_fd + 1, &readfds, NULL, NULL, &timeout);
-
-    if (sret == 0) {
+    if (!time) {
 
       fsrv->child_timed_out = 1;
       kill(fsrv->child_pid, SIGKILL);
 
-    } else {
-
-      rlen = read(fsrv->fsrv_st_fd, &status, 4);
-
     }
 
   } else {
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 7c398507..08ac15c7 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -31,10 +31,9 @@
 
 void init_cmplog_forkserver(afl_state_t *afl) {
 
-  struct timeval timeout;
-  int            st_pipe[2], ctl_pipe[2];
-  int            status;
-  s32            rlen;
+  int st_pipe[2], ctl_pipe[2];
+  int status;
+  s32 rlen;
 
   ACTF("Spinning up the cmplog fork server...");
 
@@ -185,21 +184,19 @@ void init_cmplog_forkserver(afl_state_t *afl) {
   rlen = 0;
   if (afl->fsrv.exec_tmout) {
 
-    fd_set readfds;
-    FD_ZERO(&readfds);
-    FD_SET(afl->cmplog_fsrv_st_fd, &readfds);
-    timeout.tv_sec = ((afl->fsrv.exec_tmout * FORK_WAIT_MULT) / 1000);
-    timeout.tv_usec = ((afl->fsrv.exec_tmout * FORK_WAIT_MULT) % 1000) * 1000;
+    rlen = 4;
+    u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT;
+    /* Reuse readfds as exceptfds to see when the child closed the pipe */
+    u32 time_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms);
 
-    int sret =
-        select(afl->cmplog_fsrv_st_fd + 1, &readfds, NULL, NULL, &timeout);
+    if (!time_ms) {
 
-    if (sret == 0) {
+      PFATAL("Error in timed read");
 
-      kill(afl->cmplog_fsrv_pid, SIGKILL);
-
-    } else {
+    } else if (time_ms > timeout_ms) {
 
+      afl->fsrv.child_timed_out = 1;
+      kill(afl->cmplog_fsrv_pid, SIGKILL);
       rlen = read(afl->cmplog_fsrv_st_fd, &status, 4);
 
     }
@@ -213,6 +210,11 @@ void init_cmplog_forkserver(afl_state_t *afl) {
   /* If we have a four-byte "hello" message from the server, we're all set.
      Otherwise, try to figure out what went wrong. */
 
+  if (afl->fsrv.child_timed_out)
+    FATAL(
+        "Timeout while initializing cmplog fork server (adjusting -t may "
+        "help)");
+
   if (rlen == 4) {
 
     OKF("All right - fork server is up.");
@@ -220,11 +222,6 @@ void init_cmplog_forkserver(afl_state_t *afl) {
 
   }
 
-  if (afl->fsrv.child_timed_out)
-    FATAL(
-        "Timeout while initializing cmplog fork server (adjusting -t may "
-        "help)");
-
   if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0)
     PFATAL("waitpid() failed");
 
@@ -379,16 +376,12 @@ void init_cmplog_forkserver(afl_state_t *afl) {
 
 u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
 
-  struct timeval it;
-  int            status = 0;
-  int            sret;
-  u64            exec_ms;
+  int status = 0;
+  u64 exec_ms;
 
   u32 tb4;
   s32 res;
 
-  fd_set readfds;
-
   afl->fsrv.child_timed_out = 0;
 
   /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we
@@ -423,18 +416,9 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
 
   /* Configure timeout, as requested by user, then wait for child to terminate.
    */
+  u32 time_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout);
 
-  it.tv_sec = (timeout / 1000);
-  it.tv_usec = (timeout % 1000) * 1000;
-
-  FD_ZERO(&readfds);
-  FD_SET(afl->cmplog_fsrv_st_fd, &readfds);
-  it.tv_sec = ((timeout) / 1000);
-  it.tv_usec = ((timeout) % 1000) * 1000;
-
-  sret = select(afl->cmplog_fsrv_st_fd + 1, &readfds, NULL, NULL, &it);
-
-  if (sret == 0) {
+  if (time_ms > timeout) {
 
     /* If there was no response from forkserver after timeout seconds,
     we kill the child. The forkserver should inform us afterwards */
@@ -442,9 +426,12 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
     kill(afl->cmplog_child_pid, SIGKILL);
     afl->fsrv.child_timed_out = 1;
 
+    /* After killing the child, the forkserver should tell us */
+    if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) time_ms = 0;
+
   }
 
-  if ((res = read(afl->cmplog_fsrv_st_fd, &status, 4)) != 4) {
+  if (!time_ms) {  // Something went wrong.
 
     if (afl->stop_soon) return 0;
     SAYF("\n" cLRD "[-] " cRST
@@ -467,12 +454,8 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
 
   if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0;
 
-  exec_ms = (u64)timeout - (it.tv_sec * 1000 + it.tv_usec / 1000);
   if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms;
 
-  it.tv_sec = 0;
-  it.tv_usec = 0;
-
   ++afl->total_execs;
 
   /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index b069fa77..4acc204b 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -529,9 +529,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
 
     if (!afl->shm.cmp_map->headers[k].hits) continue;
     if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS)
-      afl->stage_max += MIN(afl->shm.cmp_map->headers[k].hits, CMP_MAP_H);
+      afl->stage_max += MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_H);
     else
-      afl->stage_max += MIN(afl->shm.cmp_map->headers[k].hits, CMP_MAP_RTN_H);
+      afl->stage_max +=
+          MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_RTN_H);
 
   }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 90cb2ed5..f58e1a33 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -33,13 +33,10 @@
 u8 run_target(afl_state_t *afl, u32 timeout) {
 
   s32 res;
-  int sret;
+  u32 time_ms;
 
-  fd_set readfds;
-
-  struct timeval it;
-  int            status = 0;
-  u32            tb4;
+  int status = 0;
+  u32 tb4;
 
   afl->fsrv.child_timed_out = 0;
 
@@ -70,26 +67,20 @@ u8 run_target(afl_state_t *afl, u32 timeout) {
 
   if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
 
-  /* use select to monitor the forkserver for timeouts. */
-
-  FD_ZERO(&readfds);
-  FD_SET(afl->fsrv.fsrv_st_fd, &readfds);
-  it.tv_sec = ((timeout) / 1000);
-  it.tv_usec = ((timeout) % 1000) * 1000;
-
-  sret = select(afl->fsrv.fsrv_st_fd + 1, &readfds, NULL, NULL, &it);
+  time_ms = read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout);
 
-  if (sret == 0) {
+  if (time_ms > timeout) {
 
     /* If there was no response from forkserver after timeout seconds,
     we kill the child. The forkserver should inform us afterwards */
 
     kill(afl->fsrv.child_pid, SIGKILL);
     afl->fsrv.child_timed_out = 1;
+    if (read(afl->fsrv.fsrv_st_fd, &status, 4) < 4) time_ms = 0;
 
   }
 
-  if ((res = read(afl->fsrv.fsrv_st_fd, &status, 4)) != 4) {
+  if (!time_ms) {
 
     if (afl->stop_soon) return 0;
     SAYF("\n" cLRD "[-] " cRST