about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--README.md4
-rw-r--r--TODO1
-rw-r--r--docs/perf_tips.txt8
-rw-r--r--gcc_plugin/Makefile6
-rw-r--r--gcc_plugin/afl-gcc-fast.c2
-rw-r--r--gcc_plugin/afl-gcc-rt.o.c100
-rw-r--r--libdislocator/libdislocator.so.c4
-rw-r--r--src/afl-fuzz.c4
-rwxr-xr-xtest/test-performance.sh7
-rwxr-xr-xtest/test.sh5
11 files changed, 127 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 87c7cdef..c4269d6b 100644
--- a/Makefile
+++ b/Makefile
@@ -16,9 +16,6 @@
 # For Heiko:
 #TEST_MMAP=1
 
-PROGNAME    = afl
-VERSION     = $(shell grep '^\#define VERSION ' include/config.h | cut -d '"' -f2)
-
 PREFIX     ?= /usr/local
 BIN_PATH    = $(PREFIX)/bin
 HELPER_PATH = $(PREFIX)/lib/afl
@@ -26,6 +23,9 @@ DOC_PATH    = $(PREFIX)/share/doc/afl
 MISC_PATH   = $(PREFIX)/share/afl
 MAN_PATH    = $(PREFIX)/man/man8
 
+PROGNAME    = afl
+VERSION     = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
+
 # PROGS intentionally omit afl-as, which gets installed elsewhere.
 
 PROGS       = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
@@ -34,8 +34,8 @@ MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
 
 CFLAGS     ?= -O3 -funroll-loops
 CFLAGS     += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ \
-	      -DAFL_PATH=\"$(HELPER_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" \
-	      -DBIN_PATH=\"$(BIN_PATH)\" -Wno-unused-function
+	      -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
+              -DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function
 
 AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
 
@@ -116,7 +116,7 @@ help:
 	@echo "=========================================="
 	@echo "all: just the main afl++ binaries"
 	@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
-	@echo "source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap"
+	@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap"
 	@echo "distrib: everything (for both binary-only and source code fuzzing)"
 	@echo "man: creates simple man pages from the help option of the programs"
 	@echo "install: installs everything you have compiled with the build option above"
diff --git a/README.md b/README.md
index 4b9537d2..de012e62 100644
--- a/README.md
+++ b/README.md
@@ -55,12 +55,14 @@
   | Feature/Instrumentation | AFL-GCC | LLVM_MODE | GCC_PLUGIN | QEMU_MODE | Unicorn |
   | ----------------------- |:-------:|:---------:|:----------:|:---------:|:-------:|
   | laf-intel / CompCov     |         |     x     |            |     x     |    x    |
-  | NeverZero               |    X    |     x(1)  |            |     x     |    x    |
+  | NeverZero               |    X    |     x(1)  |      (2)   |     x     |    x    |
   | Persistent mode         |         |     x     |     X      |     x     |         |
   | Whitelist               |         |     x     |     X      |           |         |
   | InsTrim                 |         |     x     |            |           |         |
 
+  neverZero:
   (1) only in LLVM >= 9.0 due to a bug in llvm in previous versions
+  (2) gcc create non-performant code, hence it is disabled in gcc_plugin
 
 
   So all in all this is the best-of AFL that is currently out there :-)
diff --git a/TODO b/TODO
index f2642b1a..05c89679 100644
--- a/TODO
+++ b/TODO
@@ -3,6 +3,7 @@ Roadmap 2.60:
 =============
 
 afl-fuzz:
+ - change -T to use alarm() instead
  - radamsa mutator
  - test the libmutator actually works and does not run infinite (need an example though)
 
diff --git a/docs/perf_tips.txt b/docs/perf_tips.txt
index 215895b6..2fa19234 100644
--- a/docs/perf_tips.txt
+++ b/docs/perf_tips.txt
@@ -50,6 +50,9 @@ Even if you don't have a lightweight harness for a particular target, remember
 that you can always use another, related library to generate a corpus that will
 be then manually fed to a more resource-hungry program later on.
 
+Also note that reading the fuzzing input via stdin is faster than reading from
+a file.
+
 3) Use LLVM instrumentation
 ---------------------------
 
@@ -161,6 +164,11 @@ and not waste CPU time.
 
 There are several OS-level factors that may affect fuzzing speed:
 
+  - If you have no risk of power loss then run your fuzzing on a tmpfs
+    partition. This increases the performance noticably.
+    Alternatively you can use AFL_TMPDIR to point to a tmpfs location to
+    just write the input file to a tmpfs.
+
   - High system load. Use idle machines where possible. Kill any non-essential
     CPU hogs (idle browser windows, media players, complex screensavers, etc).
 
diff --git a/gcc_plugin/Makefile b/gcc_plugin/Makefile
index a603df78..287b6545 100644
--- a/gcc_plugin/Makefile
+++ b/gcc_plugin/Makefile
@@ -27,7 +27,7 @@ CFLAGS      ?= -O3 -g -funroll-loops
 CFLAGS      += -Wall -D_FORTIFY_SOURCE=2 -Wno-pointer-sign \
                -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
 
-CXXFLAGS	?= -O3 -g -funroll-loops
+CXXFLAGS    ?= -O3 -g -funroll-loops
 CXXEFLAGS   := $(CXXFLAGS) -Wall -D_FORTIFY_SOURCE=2
 
 CC          ?= gcc
@@ -35,8 +35,6 @@ CXX         ?= g++
 
 PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include"
 
-PROGS        = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
-
 ifeq "$(shell echo '\#include <sys/ipc.h>@\#include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 )" "1"
 	SHMAT_OK=1
 else
@@ -51,6 +49,8 @@ ifeq "$(TEST_MMAP)" "1"
 	LDFLAGS += -lrt
 endif
 
+PROGS        = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
+
 
 all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done
 
diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c
index b0461584..093249a0 100644
--- a/gcc_plugin/afl-gcc-fast.c
+++ b/gcc_plugin/afl-gcc-fast.c
@@ -282,6 +282,8 @@ int main(int argc, char** argv) {
         "afl-gcc-fast" VERSION cRST
         " initially by <aseipp@pobox.com>, maintainer: hexcoder-\n"
         "\n"
+        "afl-gcc-fast [options]\n"
+        "\n"
         "This is a helper application for afl-fuzz. It serves as a drop-in "
         "replacement\n"
         "for gcc, letting you recompile third-party code with the required "
diff --git a/gcc_plugin/afl-gcc-rt.o.c b/gcc_plugin/afl-gcc-rt.o.c
index dd79a0ec..5b70a247 100644
--- a/gcc_plugin/afl-gcc-rt.o.c
+++ b/gcc_plugin/afl-gcc-rt.o.c
@@ -21,12 +21,16 @@
 
 */
 
+#ifdef __ANDROID__
+#include "android-ashmem.h"
+#endif
 #include "../config.h"
 #include "../types.h"
 
 #include <stdlib.h>
 #include <signal.h>
 #include <unistd.h>
+#include <string.h>
 #include <assert.h>
 
 #include <sys/mman.h>
@@ -34,29 +38,43 @@
 #include <sys/wait.h>
 #include <sys/types.h>
 
+#include <sys/mman.h>
+#include <fcntl.h>
+
 /* Globals needed by the injected instrumentation. The __afl_area_initial region
    is used for instrumentation output before __afl_map_shm() has a chance to
    run. It will end up as .comm, so it shouldn't be too wasteful. */
 
 u8  __afl_area_initial[MAP_SIZE];
 u8 *__afl_area_ptr = __afl_area_initial;
-u32 __afl_prev_loc;
 
-/* Running in persistent mode? */
-
-static u8 is_persistent;
+#ifdef __ANDROID__
+u32 __afl_prev_loc;
+#else
+__thread u32 __afl_prev_loc;
+#endif
 
 /* Trace a basic block with some ID */
 void __afl_trace(u32 x) {
 
   u32 l = __afl_prev_loc;
-  u32 n = l ^ x;
-  *(__afl_area_ptr + n) += 1;
+
+#if 0 /* enable for neverZero feature. By default disabled since too inefficient :-( */
+  /* @Marc: avoid conditional jumps here */
+  __afl_area_ptr[l ^ x] += 1 + (__afl_area_ptr[l ^ x] == (u8)~0);
+#else
+  ++__afl_area_ptr[l ^ x];
+#endif
+
   __afl_prev_loc = (x >> 1);
   return;
 
 }
 
+/* Running in persistent mode? */
+
+static u8 is_persistent;
+
 /* SHM setup. */
 
 static void __afl_map_shm(void) {
@@ -69,9 +87,38 @@ static void __afl_map_shm(void) {
 
   if (id_str) {
 
+#ifdef USEMMAP
+    const char*    shm_file_path = id_str;
+    int            shm_fd = -1;
+    unsigned char* shm_base = NULL;
+
+    /* create the shared memory segment as if it was a file */
+    shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+    if (shm_fd == -1) {
+
+      printf("shm_open() failed\n");
+      exit(1);
+
+    }
+
+    /* map the shared memory segment to the address space of the process */
+    shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+    if (shm_base == MAP_FAILED) {
+
+      close(shm_fd);
+      shm_fd = -1;
+
+      printf("mmap() failed\n");
+      exit(2);
+
+    }
+
+    __afl_area_ptr = shm_base;
+#else
     u32 shm_id = atoi(id_str);
 
     __afl_area_ptr = shmat(shm_id, NULL, 0);
+#endif
 
     /* Whooooops. */
 
@@ -95,6 +142,8 @@ static void __afl_start_forkserver(void) {
 
   u8 child_stopped = 0;
 
+  void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
+
   /* Phone home and tell the parent that we're OK. If parent isn't there,
      assume we're not running in forkserver mode and just execute program. */
 
@@ -131,6 +180,8 @@ static void __afl_start_forkserver(void) {
 
       if (!child_pid) {
 
+        signal(SIGCHLD, old_sigchld_handler);
+
         close(FORKSRV_FD);
         close(FORKSRV_FD + 1);
         return;
@@ -176,18 +227,47 @@ int __afl_persistent_loop(unsigned int max_cnt) {
 
   if (first_pass) {
 
+    /* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.
+       On subsequent calls, the parent will take care of that, but on the first
+       iteration, it's our job to erase any trace of whatever happened
+       before the loop. */
+
+    if (is_persistent) {
+
+      memset(__afl_area_ptr, 0, MAP_SIZE);
+      __afl_area_ptr[0] = 1;
+      __afl_prev_loc = 0;
+
+    }
+
     cycle_cnt = max_cnt;
     first_pass = 0;
     return 1;
 
   }
 
-  if (is_persistent && --cycle_cnt) {
+  if (is_persistent) {
 
-    raise(SIGSTOP);
-    return 1;
+    if (--cycle_cnt) {
 
-  } else
+      raise(SIGSTOP);
+
+      __afl_area_ptr[0] = 1;
+      __afl_prev_loc = 0;
+
+      return 1;
+
+    } else {
+
+      /* When exiting __AFL_LOOP(), make sure that the subsequent code that
+         follows the loop is not traced. We do that by pivoting back to the
+         dummy output region. */
+
+      __afl_area_ptr = __afl_area_initial;
+
+    }
+
+  }
 
     return 0;
 
diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c
index f3f02c8b..7f44071a 100644
--- a/libdislocator/libdislocator.so.c
+++ b/libdislocator/libdislocator.so.c
@@ -88,7 +88,7 @@ static u8  alloc_verbose,               /* Additional debug messages        */
     hard_fail,                          /* abort() when max_mem exceeded?   */
     no_calloc_over;                     /* abort() on calloc() overflows?   */
 
-#ifdef	__OpenBSD__
+#if	defined	__OpenBSD__ || defined __APPLE__
 #define __thread
 #warning no thread support available
 #endif
@@ -121,7 +121,7 @@ static void* __dislocator_alloc(size_t len) {
   ret = mmap(NULL, (1 + PG_COUNT(len + 8)) * PAGE_SIZE, PROT_READ | PROT_WRITE,
              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 
-  if (ret == (void*)-1) {
+  if (ret == MAP_FAILED) {
 
     if (hard_fail) FATAL("mmap() failed on alloc (OOM?)");
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index bb342112..877df0d3 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -71,7 +71,9 @@ static void usage(u8* argv0) {
       "  -V seconds    - fuzz for a maximum total time of seconds then "
       "terminate\n"
       "  -E execs      - fuzz for a maximum number of total executions then "
-      "terminate\n\n"
+      "terminate\n"
+      "  Note: -V/-E are not precise, they are checked after a queue entry "
+      "is done\n  which can be many minutes/execs later\n\n"
 
       "Other stuff:\n"
       "  -T text       - text banner to show on the screen\n"
diff --git a/test/test-performance.sh b/test/test-performance.sh
index 198b58c4..87eea665 100755
--- a/test/test-performance.sh
+++ b/test/test-performance.sh
@@ -1,6 +1,10 @@
 #!/bin/bash
 
-FILE=~/.afl_performance
+# if you want a specific performance file (e.g. to compare features to another)
+# you can set the AFL_PERFORMANCE_FILE environment variable:
+FILE=$AFL_PERFORMANCE_FILE
+# otherwise we use ~/.afl_performance
+test -z "$FILE" && FILE=~/.afl_performance
 
 test -e $FILE || {
   echo Warning: This script measure the performance of afl++ and saves the result for future comparisons into $FILE
@@ -17,6 +21,7 @@ unset AFL_USE_ASAN
 unset AFL_USE_MSAN
 unset AFL_CC
 unset AFL_PRELOAD
+unset AFL_GCC_WHITELIST
 unset AFL_LLVM_WHITELIST
 unset AFL_LLVM_INSTRIM
 unset AFL_LLVM_LAF_SPLIT_SWITCHES
diff --git a/test/test.sh b/test/test.sh
index d1be014f..da0590ef 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -33,6 +33,7 @@ unset AFL_USE_ASAN
 unset AFL_USE_MSAN
 unset AFL_CC
 unset AFL_PRELOAD
+unset AFL_GCC_WHITELIST
 unset AFL_LLVM_WHITELIST
 unset AFL_LLVM_INSTRIM
 unset AFL_LLVM_LAF_SPLIT_SWITCHES
@@ -281,8 +282,8 @@ test -e ../libtokencap.so && {
 test -e ../libdislocator.so && {
   {
     ulimit -c 1
-    # DYLD_INSERT_LIBRARIES is used on Darwin/MacOSX
-    LD_PRELOAD=../libdislocator.so DYLD_INSERT_LIBRARIES=../libdislocator.so ./test-compcov BUFFEROVERFLOW > test.out 2> /dev/null
+    # DYLD_INSERT_LIBRARIES and DYLD_FORCE_FLAT_NAMESPACE is used on Darwin/MacOSX
+    LD_PRELOAD=../libdislocator.so DYLD_INSERT_LIBRARIES=../libdislocator.so DYLD_FORCE_FLAT_NAMESPACE=1 ./test-compcov BUFFEROVERFLOW > test.out 2> /dev/null
   } > /dev/null 2>&1
   grep -q BUFFEROVERFLOW test.out > /dev/null 2>&1 && {
     $ECHO "$RED[!] libdislocator did not detect the memory corruption"