Hello community, here is the log from the commit of package afl for openSUSE:Factory checked in at 2015-06-16 14:05:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/afl (Old) and /work/SRC/openSUSE:Factory/.afl.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "afl" Changes: -------- --- /work/SRC/openSUSE:Factory/afl/afl.changes 2015-06-02 10:11:50.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.afl.new/afl.changes 2015-06-16 14:05:18.000000000 +0200 @@ -1,0 +2,17 @@ +Mon Jun 15 09:07:34 UTC 2015 - astieger@suse.com + +- afl 1.83b: + * fixes for platforms other than GNU/Linux + +------------------------------------------------------------------- +Sat Jun 13 10:41:30 UTC 2015 - astieger@suse.com + +- afl 1.82b: + * Fixed a harmless but annoying race condition in persistent mode + * Updated persistent mode documentation + - Tweaked AFL_PERSISTENT to force AFL_NO_VAR_CHECK. +- afl 1.81b: + * Added persistent mode for in-process fuzzing. + * in-place resume code to preserve crashes/README.txt. + +------------------------------------------------------------------- Old: ---- afl-1.80b.tgz New: ---- afl-1.83b.tgz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ afl.spec ++++++ --- /var/tmp/diff_new_pack.Is5hsv/_old 2015-06-16 14:05:19.000000000 +0200 +++ /var/tmp/diff_new_pack.Is5hsv/_new 2015-06-16 14:05:19.000000000 +0200 @@ -17,7 +17,7 @@ Name: afl -Version: 1.80b +Version: 1.83b Release: 0 Summary: American fuzzy lop is a security-oriented fuzzer License: Apache-2.0 ++++++ afl-1.80b.tgz -> afl-1.83b.tgz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/Makefile new/afl-1.83b/Makefile --- old/afl-1.80b/Makefile 2015-05-26 07:20:29.000000000 +0200 +++ new/afl-1.83b/Makefile 2015-06-14 16:34:26.000000000 +0200 @@ -14,7 +14,7 @@ # PROGNAME = afl -VERSION = 1.80b +VERSION = 1.83b PREFIX ?= /usr/local BIN_PATH = $(PREFIX)/bin @@ -124,7 +124,7 @@ test "`basename $$PWD`" = "afl" || exit 1 test -f ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz; if [ "$$?" = "0" ]; then echo; echo "Change program version in Makefile, mmkay?"; echo; exit 1; fi cd ..; rm -rf $(PROGNAME)-$(VERSION); cp -pr $(PROGNAME) $(PROGNAME)-$(VERSION); \ - tar -cvz --exclude openssl-null-ptr2.der -f ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz $(PROGNAME)-$(VERSION) + tar -cvz -f ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz $(PROGNAME)-$(VERSION) chmod 644 ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz ( cd ~/www/afl/releases/; ln -s -f $(PROGNAME)-$(VERSION).tgz $(PROGNAME)-latest.tgz ) cat docs/README >~/www/afl/README.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/afl-as.h new/afl-1.83b/afl-as.h --- old/afl-1.80b/afl-as.h 2015-04-08 08:47:29.000000000 +0200 +++ new/afl-1.83b/afl-as.h 2015-06-11 08:33:07.000000000 +0200 @@ -295,7 +295,7 @@ " call write\n" " addl $12, %esp\n" "\n" - " pushl $2 /* WUNTRACED */\n" + " pushl $0 /* no flags */\n" " pushl $__afl_temp /* status */\n" " pushl __afl_fork_pid /* PID */\n" " call waitpid\n" @@ -574,7 +574,7 @@ " movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n" CALL_L64("write") "\n" - " movq $2, %rdx /* WUNTRACED */\n" + " movq $0, %rdx /* no flags */\n" " leaq __afl_temp(%rip), %rsi /* status */\n" " movq __afl_fork_pid(%rip), %rdi /* PID */\n" CALL_L64("waitpid") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/afl-cmin new/afl-1.83b/afl-cmin --- old/afl-1.80b/afl-cmin 2015-05-24 05:01:18.000000000 +0200 +++ new/afl-1.83b/afl-cmin 2015-06-14 16:33:53.000000000 +0200 @@ -337,8 +337,8 @@ echo "[*] Sorting trace sets (this may take a while)..." -ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | xargs -d '\n' -n 1 cat | sort | \ - uniq -c | sort -n >"$TRACE_DIR/.all_uniq" +ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \ + sort | uniq -c | sort -n >"$TRACE_DIR/.all_uniq" TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/afl-fuzz.c new/afl-1.83b/afl-fuzz.c --- old/afl-1.80b/afl-fuzz.c 2015-05-24 04:15:53.000000000 +0200 +++ new/afl-1.83b/afl-fuzz.c 2015-06-12 09:50:07.000000000 +0200 @@ -1957,7 +1957,7 @@ if (child_timed_out) FATAL("Timeout while initializing fork server (adjusting -t may help)"); - if (waitpid(forksrv_pid, &status, WUNTRACED) <= 0) + if (waitpid(forksrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed"); if (WIFSIGNALED(status)) { @@ -2090,6 +2090,8 @@ static u8 run_target(char** argv) { static struct itimerval it; + static u32 prev_timed_out = 0; + int status = 0; u32 tb4; @@ -2189,7 +2191,7 @@ /* 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 ((res = write(fsrv_ctl_fd, &status, 4)) != 4) { + if ((res = write(fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { if (stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); @@ -2218,7 +2220,7 @@ if (dumb_mode == 1 || no_forkserver) { - if (waitpid(child_pid, &status, WUNTRACED) <= 0) PFATAL("waitpid() failed"); + if (waitpid(child_pid, &status, 0) <= 0) PFATAL("waitpid() failed"); } else { @@ -2255,6 +2257,8 @@ classify_counts((u32*)trace_bits); #endif /* ^__x86_64__ */ + prev_timed_out = child_timed_out; + /* Report outcome to caller. */ if (child_timed_out) return FAULT_HANG; @@ -3487,9 +3491,13 @@ /* All right, let's do <out_dir>/crashes/id:* and <out_dir>/hangs/id:*. */ - fn = alloc_printf("%s/crashes/README.txt", out_dir); - unlink(fn); /* Ignore errors */ - ck_free(fn); + if (!in_place_resume) { + + fn = alloc_printf("%s/crashes/README.txt", out_dir); + unlink(fn); /* Ignore errors */ + ck_free(fn); + + } fn = alloc_printf("%s/crashes", out_dir); @@ -6401,14 +6409,14 @@ static void handle_timeout(int sig) { - child_timed_out = 1; - if (child_pid > 0) { + child_timed_out = 1; kill(child_pid, SIGKILL); } else if (child_pid == -1 && forksrv_pid > 0) { + child_timed_out = 1; kill(forksrv_pid, SIGKILL); } @@ -7439,9 +7447,11 @@ } - if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; - if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; - if (getenv("AFL_NO_VAR_CHECK")) no_var_check = 1; + if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; + if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; + + if (getenv("AFL_NO_VAR_CHECK") || getenv("AFL_PERSISTENT")) + no_var_check = 1; if (dumb_mode == 2 && no_forkserver) FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/afl-showmap.c new/afl-1.83b/afl-showmap.c --- old/afl-1.80b/afl-showmap.c 2015-04-28 18:07:42.000000000 +0200 +++ new/afl-1.83b/afl-showmap.c 2015-06-12 09:37:12.000000000 +0200 @@ -278,7 +278,7 @@ setitimer(ITIMER_REAL, &it, NULL); - if (waitpid(child_pid, &status, WUNTRACED) <= 0) FATAL("waitpid() failed"); + if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed"); child_pid = 0; it.it_value.tv_sec = 0; @@ -337,6 +337,8 @@ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" "msan_track_origins=0", 0); + unsetenv("AFL_PERSISTENT"); + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/afl-tmin.c new/afl-1.83b/afl-tmin.c --- old/afl-1.80b/afl-tmin.c 2015-04-28 18:09:30.000000000 +0200 +++ new/afl-1.83b/afl-tmin.c 2015-06-12 09:37:17.000000000 +0200 @@ -302,7 +302,7 @@ setitimer(ITIMER_REAL, &it, NULL); - if (waitpid(child_pid, &status, WUNTRACED) <= 0) FATAL("waitpid() failed"); + if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed"); child_pid = 0; it.it_value.tv_sec = 0; @@ -684,6 +684,8 @@ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" "msan_track_origins=0", 0); + unsetenv("AFL_PERSISTENT"); + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/ChangeLog new/afl-1.83b/docs/ChangeLog --- old/afl-1.80b/docs/ChangeLog 2015-05-26 07:21:17.000000000 +0200 +++ new/afl-1.83b/docs/ChangeLog 2015-06-14 16:33:18.000000000 +0200 @@ -17,6 +17,40 @@ to get on with the times. -------------- +Version 1.83b: +-------------- + + - Fixed a problem with xargs -d on non-Linux systems in afl-cmin. Spotted by + teor2345 and Ben Nagy. + + - Fixed an implicit declaration in LLVM mode on MacOS X. Reported by + Kai Zhao. + +-------------- +Version 1.82b: +-------------- + + - Fixed a harmless but annoying race condition in persistent mode - signal + delivery is a bit more finicky than I thought. + + - Updated the documentation to explain persistent mode a bit better. + + - Tweaked AFL_PERSISTENT to force AFL_NO_VAR_CHECK. + +-------------- +Version 1.81b: +-------------- + + - Added persistent mode for in-process fuzzing. See llvm_mode/README.llvm. + Inspired by Kostya Serebryany and Christian Holler. + + - Changed the in-place resume code to preserve crashes/README.txt. Suggested + by Ben Nagy. + + - Included a potential fix for LLVM mode issues on MacOS X, based on the + investigation done by teor2345. + +-------------- Version 1.80b: -------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/README new/afl-1.83b/docs/README --- old/afl-1.80b/docs/README 2015-05-20 22:50:29.000000000 +0200 +++ new/afl-1.83b/docs/README 2015-06-11 08:53:02.000000000 +0200 @@ -419,7 +419,7 @@ Sam Hakim Laszlo Szekeres David A. Wheeler Turo Lamminen Andreas Stieger Richard Godbee - Louis Dassy + Louis Dassy teor2345 Thank you! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/env_variables.txt new/afl-1.83b/docs/env_variables.txt --- old/afl-1.80b/docs/env_variables.txt 2015-05-24 04:16:53.000000000 +0200 +++ new/afl-1.83b/docs/env_variables.txt 2015-06-11 08:42:08.000000000 +0200 @@ -139,6 +139,9 @@ (Technically speaking, the setting is passed down to the binary itself, and not handled in any special way by afl-fuzz.) + - In LLVM mode, AFL_PERSISTENT can be set to fuzz in persistent mode. See + llvm_mode/README.llvm for additional information on what this means. + - In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace. 4) Settings for afl-qemu-trace diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/perf_tips.txt new/afl-1.83b/docs/perf_tips.txt --- old/afl-1.80b/docs/perf_tips.txt 2015-05-01 05:11:29.000000000 +0200 +++ new/afl-1.83b/docs/perf_tips.txt 2015-06-11 08:47:54.000000000 +0200 @@ -57,6 +57,10 @@ the LLVM-based instrumentation mode described in llvm_mode/README.llvm. Note that this mode requires the use of clang and will not work with GCC. +The LLVM mode also offers a "persistent", in-process fuzzing mode that can +work well for certain types of self-contained libraries, and for fast targets, +can offer performance gains up to 5-10x. + 4) Have a closer look at the binary ----------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/sister_projects.txt new/afl-1.83b/docs/sister_projects.txt --- old/afl-1.80b/docs/sister_projects.txt 2015-05-20 22:49:46.000000000 +0200 +++ new/afl-1.83b/docs/sister_projects.txt 2015-06-12 03:49:03.000000000 +0200 @@ -48,7 +48,9 @@ -------------------------------------------------------- Provides an evolutionary instrumentation-guided fuzzing harness that allows - some programs to be fuzzed without the fork / execve overhead. + some programs to be fuzzed without the fork / execve overhead. (Similar + functionality is now available as the "persistent" feature described in + ../llvm_mode/README.llvm.) http://llvm.org/docs/LibFuzzer.html @@ -113,6 +115,13 @@ https://github.com/MartijnB/disfuzz-afl +afl-launch (Ben Nagy) +--------------------- + + Another AFL launcher utility with a simple CLI. + + https://github.com/bnagy/afl-launch + AFL fixup shim (Ben Nagy) ------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/docs/technical_details.txt new/afl-1.83b/docs/technical_details.txt --- old/afl-1.80b/docs/technical_details.txt 2015-04-20 05:40:05.000000000 +0200 +++ new/afl-1.83b/docs/technical_details.txt 2015-06-11 20:14:50.000000000 +0200 @@ -413,9 +413,17 @@ afl-fuzz. With fast targets, the fork server can offer considerable performance gains, -usually between 1.5x and 2x. It is also possible to use the fork server in -manual mode, skipping over larger, user-selected chunks of initialization -code. With some targets, this can produce 10x+ performance gain. +usually between 1.5x and 2x. It is also possible to: + + - Use the fork server in manual ("deferred") mode, skipping over larger, + user-selected chunks of initialization code. With some targets, this can + produce 10x+ performance gains. + + - Enable "persistent" mode, where a single process is used to try out + multiple inputs, greatly limiting the overhead of repetitive fork() + calls. As with the previous mode, this requires custom modifications, + but can improve the performance of fast targets by a factor of 5 or more + - approximating the benefits of in-process fuzzing jobs. 11) Parallelization ------------------- Files old/afl-1.80b/docs/vuln_samples/openssl-null-ptr2.der and new/afl-1.83b/docs/vuln_samples/openssl-null-ptr2.der differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/experimental/README.experiments new/afl-1.83b/experimental/README.experiments --- old/afl-1.80b/experimental/README.experiments 2015-04-30 06:46:48.000000000 +0200 +++ new/afl-1.83b/experimental/README.experiments 2015-06-11 19:13:37.000000000 +0200 @@ -28,6 +28,9 @@ - libpng_no_checksum - a sample patch for removing CRC checks in libpng. + - persistent_demo - an example of how to use the LLVM persistent process + mode to speed up certain fuzzing jobs. + - post_library - an example of how to build postprocessors for AFL. Note that the minimize_corpus.sh tool has graduated from the experimental/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/experimental/persistent_demo/persistent_demo.c new/afl-1.83b/experimental/persistent_demo/persistent_demo.c --- old/afl-1.80b/experimental/persistent_demo/persistent_demo.c 1970-01-01 01:00:00.000000000 +0100 +++ new/afl-1.83b/experimental/persistent_demo/persistent_demo.c 2015-06-12 08:29:11.000000000 +0200 @@ -0,0 +1,102 @@ +/* + american fuzzy lop - persistent mode example + -------------------------------------------- + + Written and maintained by Michal Zalewski <lcamtuf@google.com> + + Copyright 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This file demonstrates the high-performance "persistent mode" that may be + suitable for fuzzing certain fast and well-behaved libraries, provided that + they are stateless or that their internal state can be easily reset + across runs. + + To make this work, the library and this shim need to be compiled in LLVM + mode using afl-clang-fast (other compiler wrappers will *not* work); and + afl-fuzz must be called with AFL_PERSISTENT set. + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> + +/* This constant specifies the number of inputs to process before restarting. + This is optional, but helps limit the impact of memory leaks and similar + hiccups. */ + +#define PERSIST_MAX 1000 + +unsigned int persist_cnt; + + +/* Main entry point. */ + +int main(int argc, char** argv) { + + char buf[100]; /* Example-only buffer, you'd replace it with other global or + local variables appropriate for your use case. */ + +try_again: + + /*** PLACEHOLDER CODE ***/ + + /* STEP 1: Fully re-initialize all critical variables. In our example, this + involves zeroing buf[], our input buffer. */ + + memset(buf, 0, 100); + + /* STEP 2: Read input data. When reading from stdin, no special preparation + is required. When reading from a named file, you need to close the + old descriptor and reopen the file first! + + Beware of reading from buffered FILE* objects such as stdin. Use + raw file descriptors or call fopen() / fdopen() in every pass. */ + + read(0, buf, 100); + + /* STEP 3: This is where we'd call the tested library on the read data. Here, + we just have some trivial inline code that faults on 'foo!'. */ + + if (buf[0] == 'f') { + printf("one\n"); + if (buf[1] == 'o') { + printf("two\n"); + if (buf[2] == 'o') { + printf("three\n"); + if (buf[3] == '!') { + printf("four\n"); + abort(); + } + } + } + } + + /*** END PLACEHOLDER CODE ***/ + + /* STEP 4: To signal successful completion of a run, we need to deliver + SIGSTOP to our own process, then loop to the very beginning + once we're resumed by the supervisor process. We do this only + if AFL_PERSISTENT is set to retain normal behavior when the + program is executed directly; and take note of PERSIST_MAX. */ + + if (getenv("AFL_PERSISTENT") && persist_cnt++ < PERSIST_MAX) { + + raise(SIGSTOP); + goto try_again; + + } + + /* If AFL_PERSISTENT not set or PERSIST_MAX exceeded, exit normally. */ + + return 0; + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/llvm_mode/Makefile new/afl-1.83b/llvm_mode/Makefile --- old/afl-1.80b/llvm_mode/Makefile 2015-04-24 21:12:52.000000000 +0200 +++ new/afl-1.83b/llvm_mode/Makefile 2015-06-11 09:25:52.000000000 +0200 @@ -36,6 +36,14 @@ CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti $(CXXFLAGS) CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) +# User teor2345 reports that this is required to make things work on MacOS X. + +ifeq "$(shell uname)" "Darwin" + +CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress + +endif + # We were using llvm-config --bindir to get the location of clang, but # this seems to be busted on some distros, so using the one in $PATH is # probably better. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/llvm_mode/README.llvm new/afl-1.83b/llvm_mode/README.llvm --- old/afl-1.80b/llvm_mode/README.llvm 2015-05-02 23:20:17.000000000 +0200 +++ new/afl-1.83b/llvm_mode/README.llvm 2015-06-12 09:15:10.000000000 +0200 @@ -80,8 +80,8 @@ This is an early-stage mechanism, so field reports are welcome. You can send bug reports to <afl-users@googlegroups.com>. -4) Bonus feature: deferred instrumentation ------------------------------------------- +4) Bonus feature #1: deferred instrumentation +--------------------------------------------- AFL tries to optimize performance by executing the targeted binary just once, stopping it just before main(), and then cloning this "master" process to get @@ -97,7 +97,7 @@ attempts to read the fuzzed input and parse it. You can do this in LLVM mode in a fairly simple way: -1) First, locate a suitable location in the code for the deferred initialization +1. First, locate a suitable location in the code for the deferred initialization to take place. This needs to be done with *extreme* care to avoid breaking the binary. In particular, the program will probably malfunction if the initialization happens after: @@ -116,7 +116,7 @@ at all and the program is allowed to exit before that; in this case, afl-fuzz will complain about failed handshake and bail out. -2) Next, insert the following global function declaration somewhere in the +2. Next, insert the following global function declaration somewhere in the source file: void __afl_manual_init(void); @@ -126,7 +126,7 @@ can put this in between #ifdef __AFL_HAVE_MANUAL_INIT to allow the code to build correctly without afl-clang-fast. -3) Finally, be sure to set AFL_DEFER_FORKSRV=1 before invoking afl-fuzz. +3. Finally, be sure to set AFL_DEFER_FORKSRV=1 before invoking afl-fuzz. Again, this feature is easy to misuse; be careful and double-test that the coverage and the number of discovered paths is comparable between normal and @@ -134,3 +134,37 @@ so: https://groups.google.com/forum/#!topic/afl-users/fNMJHl7Fhzs + +5) Bonus feature #2: persistent mode +------------------------------------ + +Some libraries provide APIs that are stateless, or whose state can be reset in +between processing different input files. When such a reset is performed, a +single long-lived process can be reused to try out multiple test cases, +eliminating the need for repeated fork() calls and the associated OS overhead: + + http://lcamtuf.blogspot.com/2015/06/new-in-afl-persistent-mode.html + +With certain fast targets, such an approach can offer dramatic (5x+) +performance gains. The LLVM mode allows you to build such persistent targets +using the template provided in ../experimental/persistent_demo/. + +To leverage this functionality, you need to set AFL_PERSISTENT before +invoking afl-fuzz, and the target binary needs to incorporate a simple pattern +documented in the aforementioned example file. It also needs to be compiled with +afl-clang-fast; other compiler wrappers will not work. + +Note that as with the previous mode, the feature is easy to misuse; if you +do not reset the critical state fully, you may end up with false positives or +waste a whole lot of CPU power doing nothing useful at all. Be particularly +wary of memory leaks. + +When running in this mode, the execution paths will inherently vary a bit +depending on whether the input loop is being entered for the first time or +executed again. To avoid spurious warnings, AFL_PERSISTENT implies +AFL_NO_VAR_CHECK and hides the "variable path" warnings in the UI. + +PS. Because there are task switches still involved, the mode isn't as fast as +"pure" in-process fuzzing offered, say, by LLVM's LibFuzzer; but it is a lot +faster than the normal fork() model, and compared to in-process fuzzing, +should be a lot more robust. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/llvm_mode/afl-llvm-rt.o.c new/afl-1.83b/llvm_mode/afl-llvm-rt.o.c --- old/afl-1.80b/llvm_mode/afl-llvm-rt.o.c 2015-04-16 08:12:29.000000000 +0200 +++ new/afl-1.83b/llvm_mode/afl-llvm-rt.o.c 2015-06-12 10:25:16.000000000 +0200 @@ -23,11 +23,14 @@ #include "../types.h" #include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <assert.h> + #include <sys/mman.h> #include <sys/shm.h> #include <sys/wait.h> -#include <unistd.h> -#include <assert.h> +#include <sys/types.h> /* Globals needed by the injected instrumentation. The __afl_area_initial region @@ -38,6 +41,7 @@ u8* __afl_area_ptr = __afl_area_initial; u16 __afl_prev_loc; + /* SHM setup. */ static void __afl_map_shm(void) { @@ -73,6 +77,10 @@ static void __afl_start_forkserver(void) { static u8 tmp[4]; + s32 child_pid; + + u8 child_stopped = 0; + u8 use_persistent = !!getenv("AFL_PERSISTENT"); /* 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. */ @@ -81,32 +89,61 @@ while (1) { - s32 child_pid; + u32 was_killed; int status; /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, tmp, 4) != 4) exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(1); + + /* If we stopped the child in persistent mode, but there was a race + condition and afl-fuzz already issued SIGKILL, write off the old + process. */ + + if (child_stopped && was_killed) { + child_stopped = 0; + if (waitpid(child_pid, &status, 0) < 0) exit(1); + } + + if (!child_stopped) { + + /* Once woken up, create a clone of our process. */ + + child_pid = fork(); + if (child_pid < 0) exit(1); - /* Once woken up, create a clone of our process. */ + /* In child process: close fds, resume execution. */ - child_pid = fork(); - if (child_pid < 0) exit(1); + if (!child_pid) { - /* In child process: close fds, resume execution. */ + close(FORKSRV_FD); + close(FORKSRV_FD + 1); + return; + + } - if (!child_pid) { + } else { - close(FORKSRV_FD); - close(FORKSRV_FD + 1); - return; + /* Special handling for persistent mode: if the child is alive but + currently stopped, simply restart it with SIGCONT. */ + + kill(child_pid, SIGCONT); + child_stopped = 0; } /* In parent process: write PID to pipe, then wait for child. */ if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(1); - if (waitpid(child_pid, &status, WUNTRACED) < 0) exit(1); + + if (waitpid(child_pid, &status, use_persistent ? WUNTRACED : 0) < 0) + exit(1); + + /* In persistent mode, the child stops itself with SIGSTOP to indicate + a successful run. In this case, we want to wake it up without forking + again. */ + + if (WIFSTOPPED(status)) child_stopped = 1; /* Relay wait status to pipe, then loop back. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-1.80b/qemu_mode/patches/afl-qemu-cpu-inl.h new/afl-1.83b/qemu_mode/patches/afl-qemu-cpu-inl.h --- old/afl-1.80b/qemu_mode/patches/afl-qemu-cpu-inl.h 2015-04-10 04:09:16.000000000 +0200 +++ new/afl-1.83b/qemu_mode/patches/afl-qemu-cpu-inl.h 2015-06-11 08:33:30.000000000 +0200 @@ -211,7 +211,7 @@ /* Get and relay exit status to parent. */ - if (waitpid(child_pid, &status, WUNTRACED) < 0) exit(6); + if (waitpid(child_pid, &status, 0) < 0) exit(6); if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); }