diff --git a/Makefile b/Makefile index 44d1ffa..72d62cf 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # # Written and maintained by Michal Zalewski # -# Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. +# Copyright 2013, 2014, 2015, 2016, 2017 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. @@ -111,8 +111,8 @@ all_done: test_build .NOTPARALLEL: clean clean: - rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.3.0.tar.bz2 afl-qemu-trace - rm -rf out_dir qemu_mode/qemu-2.3.0 + rm -f $(PROGS) my-afl-as afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.10.0.tar.bz2 afl-qemu-trace + rm -rf out_dir qemu_mode/qemu-2.10.0 $(MAKE) -C llvm_mode clean $(MAKE) -C libdislocator clean $(MAKE) -C libtokencap clean diff --git a/afl-analyze.c b/afl-analyze.c index b724ecd..d794481 100644 --- a/afl-analyze.c +++ b/afl-analyze.c @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2016 Google Inc. All rights reserved. + Copyright 2016, 2017 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. @@ -72,6 +72,7 @@ static s32 shm_id, /* ID of the SHM region */ dev_null_fd = -1; /* FD to /dev/null */ static u8 edges_only, /* Ignore hit counts? */ + use_hex_offsets, /* Show hex offsets? */ use_stdin = 1; /* Use stdin for program input? */ static volatile u8 @@ -490,9 +491,13 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) { /* Every 16 digits, display offset. */ if (!((i + off) % 16)) { - + if (off) SAYF(cRST cLCY ">"); - SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off); + + if (use_hex_offsets) + SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off); + else + SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off); } @@ -516,7 +521,10 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) { #else - SAYF(" Offset %u, length %u: ", i, rlen); + if (use_hex_offsets) + SAYF(" Offset %x, length %u: ", i, rlen); + else + SAYF(" Offset %u, length %u: ", i, rlen); switch (rtype) { @@ -878,6 +886,10 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); u8 *tmp, *cp, *rsl, *own_copy; + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); /* Now we need to actually find qemu for argv[0]. */ @@ -1030,6 +1042,8 @@ int main(int argc, char** argv) { if (optind == argc || !in_file) usage(argv[0]); + use_hex_offsets = !!getenv("AFL_ANALYZE_HEX"); + setup_shm(); setup_signal_handlers(); diff --git a/afl-fuzz.c b/afl-fuzz.c index 2c6c8ae..9bd380f 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -6,7 +6,7 @@ Forkserver design by Jann Horn - Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016, 2017 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. @@ -124,7 +124,9 @@ EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ qemu_mode, /* Running in QEMU mode? */ skip_requested, /* Skip request, via SIGUSR1 */ run_over10m, /* Run time over 10 minutes? */ - persistent_mode; /* Running in persistent mode? */ + persistent_mode, /* Running in persistent mode? */ + deferred_mode, /* Deferred forkserver mode? */ + fast_cal; /* Try to calibrate faster? */ static s32 out_fd, /* Persistent fd for out_file */ dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ @@ -2437,11 +2439,14 @@ static u8 run_target(char** argv, u32 timeout) { /* Report outcome to caller. */ - if (child_timed_out) return FAULT_TMOUT; - if (WIFSIGNALED(status) && !stop_soon) { + kill_signal = WTERMSIG(status); + + if (child_timed_out && kill_signal == SIGKILL) return FAULT_TMOUT; + return FAULT_CRASH; + } /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and @@ -2552,7 +2557,7 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, q->cal_failed++; stage_name = "calibration"; - stage_max = CAL_CYCLES; + stage_max = fast_cal ? 3 : CAL_CYCLES; /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ @@ -3204,6 +3209,12 @@ static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { write_to_testcase(mem, len); new_fault = run_target(argv, hang_tmout); + /* A corner case that one user reported bumping into: increasing the + timeout actually uncovers a crash. Make sure we don't discard it if + so. */ + + if (!stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash; + if (stop_soon || new_fault != FAULT_TMOUT) return keeping; } @@ -3228,6 +3239,8 @@ static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { case FAULT_CRASH: +keep_as_crash: + /* This is handled in a manner roughly similar to timeouts, except for slightly different limits and no need to re-run test cases. */ @@ -3420,6 +3433,7 @@ static void write_stats_file(double bitmap_cvg, double stability, double eps) { "exec_timeout : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" + "target_mode : %s%s%s%s%s%s%s\n" "command_line : %s\n", start_time / 1000, get_cur_time() / 1000, getpid(), queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, @@ -3428,7 +3442,13 @@ static void write_stats_file(double bitmap_cvg, double stability, double eps) { queued_variable, stability, bitmap_cvg, unique_crashes, unique_hangs, last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000, total_execs - last_crash_execs, - exec_tmout, use_banner, orig_cmdline); + exec_tmout, use_banner, + qemu_mode ? "qemu " : "", dumb_mode ? " dumb " : "", + no_forkserver ? "no_forksrv " : "", crash_mode ? "crash " : "", + persistent_mode ? "persistent " : "", deferred_mode ? "deferred " : "", + (qemu_mode || dumb_mode || no_forkserver || crash_mode || + persistent_mode || deferred_mode) ? "" : "default", + orig_cmdline); /* ignore errors */ fclose(f); @@ -3693,9 +3713,13 @@ static void maybe_delete_out_dir(void) { /* Okay, let's get the ball rolling! First, we need to get rid of the entries in /.synced/.../id:*, if any are present. */ - fn = alloc_printf("%s/.synced", out_dir); - if (delete_files(fn, NULL)) goto dir_cleanup_failed; - ck_free(fn); + if (!in_place_resume) { + + fn = alloc_printf("%s/.synced", out_dir); + if (delete_files(fn, NULL)) goto dir_cleanup_failed; + ck_free(fn); + + } /* Next, we need to clean up /queue/.state/ subdirectories: */ @@ -4424,7 +4448,8 @@ static void show_init_stats(void) { } -/* Find first power of two greater or equal to val. */ +/* Find first power of two greater or equal to val (assuming val under + 2^31). */ static u32 next_p2(u32 val) { @@ -6933,6 +6958,7 @@ EXP_ST void check_binary(u8* fname) { OKF(cPIN "Deferred forkserver binary detected."); setenv(DEFER_ENV_VAR, "1", 1); + deferred_mode = 1; } else if (getenv("AFL_DEFER_FORKSRV")) { @@ -7132,7 +7158,10 @@ EXP_ST void setup_dirs_fds(void) { if (sync_id) { tmp = alloc_printf("%s/.synced/", out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + + if (mkdir(tmp, 0700) && (!in_place_resume || errno != EEXIST)) + PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); } @@ -7580,6 +7609,10 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); u8 *tmp, *cp, *rsl, *own_copy; + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); new_argv[2] = target_path; @@ -7887,8 +7920,9 @@ int main(int argc, char** argv) { if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; - if (getenv("AFL_NO_ARITH")) no_arith = 1; + if (getenv("AFL_NO_ARITH")) no_arith = 1; if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; + if (getenv("AFL_FAST_CAL")) fast_cal = 1; if (getenv("AFL_HANG_TMOUT")) { hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); diff --git a/afl-showmap.c b/afl-showmap.c index 0594f6a..8d6fcd6 100644 --- a/afl-showmap.c +++ b/afl-showmap.c @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016, 2017 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. @@ -297,6 +297,8 @@ static void run_target(char** argv) { if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); + setsid(); + execv(target_path, argv); *(u32*)trace_bits = EXEC_FAIL_SIG; @@ -561,6 +563,10 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); u8 *tmp, *cp, *rsl, *own_copy; + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); new_argv[2] = target_path; diff --git a/afl-tmin.c b/afl-tmin.c index ef10478..bf4873b 100644 --- a/afl-tmin.c +++ b/afl-tmin.c @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 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. @@ -287,6 +287,8 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) { close(dev_null_fd); close(prog_in_fd); + setsid(); + if (mem_limit) { r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; @@ -343,8 +345,11 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) { total_execs++; if (stop_soon) { + SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST); + close(write_to_file(out_file, in_data, in_len)); exit(1); + } /* Always discard inputs that time out. */ @@ -893,6 +898,10 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); u8 *tmp, *cp, *rsl, *own_copy; + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); /* Now we need to actually find qemu for argv[0]. */ diff --git a/config.h b/config.h index 4ba09a2..e74b3b3 100644 --- a/config.h +++ b/config.h @@ -21,7 +21,7 @@ /* Version string: */ -#define VERSION "2.49b" +#define VERSION "2.52b" /****************************************************** * * diff --git a/docs/ChangeLog b/docs/ChangeLog index 58344bb..a1b7da6 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -16,6 +16,49 @@ Not sure if you should upgrade? The lowest currently recommended version is 2.41b. If you're stuck on an earlier release, it's strongly advisable to get on with the times. +--------------------------- +Version 2.52b (2017-11-04): +--------------------------- + + - Upgraded QEMU patches from 2.3.0 to 2.10.0. Required troubleshooting + several weird issues. All the legwork done by Andrew Griffiths. + + - Added setsid to afl-showmap. See the notes for 2.51b. + + - Added target mode (deferred, persistent, qemu, etc) to fuzzer_stats. + Requested by Jakub Wilk. + + - afl-tmin should now save a partially minimized file when Ctrl-C + is pressed. Suggested by Jakub Wilk. + + - Added an option for afl-analyze to dump offsets in hex. Suggested by + Jakub Wilk. + + - Added support for parameters in triage_crashes.sh. Patch by Adam of + DC949. + +--------------------------- +Version 2.51b (2017-08-30): +--------------------------- + + - Made afl-tmin call setsid to prevent glibc traceback junk from showing + up on the terminal in some distros. Suggested by Jakub Wilk. + +--------------------------- +Version 2.50b (2017-08-19): +--------------------------- + + - Fixed an interesting timing corner case spotted by Jakub Wilk. + + - Addressed a libtokencap / pthreads incompatibility issue. Likewise, spotted + by Jakub Wilk. + + - Added a mention of afl-kit and Pythia. + + - Added AFL_FAST_CAL. + + - In-place resume now preserves .synced. Suggested by Jakub Wilk. + --------------------------- Version 2.49b (2017-07-18): --------------------------- diff --git a/docs/env_variables.txt b/docs/env_variables.txt index 2ae2812..71f72af 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -145,6 +145,9 @@ checks or alter some of the more exotic semantics of the tool: mutated files - say, to fix up checksums. See experimental/post_library/ for more. + - AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less + precise), which can help when starting a session against a slow target. + - The CPU widget shown at the bottom of the screen is fairly simplistic and may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set AFL_NO_CPU_RED. @@ -210,7 +213,13 @@ to match when minimizing crashes. This will make minimization less useful, but may prevent the tool from "jumping" from one crashing condition to another in very buggy software. You probably want to combine it with the -e flag. -7) Settings for libdislocator.so +7) Settings for afl-analyze +--------------------------- + +You can set AFL_ANALYZE_HEX to get file offsets printed as hexadecimal instead +of decimal. + +8) Settings for libdislocator.so -------------------------------- The library honors three environmental variables: @@ -230,14 +239,14 @@ The library honors three environmental variables: of the common allocators check for that internally and return NULL, so it's a security risk only in more exotic setups. -8) Settings for libtokencap.so +9) Settings for libtokencap.so ------------------------------ This library accepts AFL_TOKEN_FILE to indicate the location to which the discovered tokens should be written. -9) Third-party variables set by afl-fuzz & other tools ------------------------------------------------------- +10) Third-party variables set by afl-fuzz & other tools +------------------------------------------------------- Several variables are not directly interpreted by afl-fuzz, but are set to optimal values if not already present in the environment: diff --git a/docs/sister_projects.txt b/docs/sister_projects.txt index 1d87acb..41701e2 100644 --- a/docs/sister_projects.txt +++ b/docs/sister_projects.txt @@ -228,6 +228,14 @@ afl-ddmin-mod (Markus Teufelberger) https://github.com/MarkusTeufelberger/afl-ddmin-mod +afl-kit (Kuang-che Wu) +---------------------- + + Replacements for afl-cmin and afl-tmin with additional features, such + as the ability to filter crashes based on stderr patterns. + + https://github.com/kcwu/afl-kit + ------------------------------- Narrow-purpose or experimental: ------------------------------- @@ -336,3 +344,11 @@ CGI wrapper (floyd) Facilitates the testing of CGI scripts. https://github.com/floyd-fuh/afl-cgi-wrapper + +Fuzzing difficulty estimation (Marcel Boehme) +--------------------------------------------- + + A fork of AFL that tries to quantify the likelihood of finding additional + paths or crashes at any point in a fuzzing job. + + https://github.com/mboehme/pythia diff --git a/docs/status_screen.txt b/docs/status_screen.txt index 4502a36..d4c37df 100644 --- a/docs/status_screen.txt +++ b/docs/status_screen.txt @@ -297,7 +297,8 @@ wait a couple of cycles to get their chance). Next, we have the number of new paths found during this fuzzing section and imported from other fuzzer instances when doing parallelized fuzzing; and the -number of inputs that produce seemingly variable behavior in the tested binary. +extent to which identical inputs appear to sometimes produce variable behavior +in the tested binary. That last bit is actually fairly interesting: it measures the consistency of observed traces. If a program always behaves the same for the same input data, diff --git a/experimental/crash_triage/triage_crashes.sh b/experimental/crash_triage/triage_crashes.sh index 516804c..5894a4d 100755 --- a/experimental/crash_triage/triage_crashes.sh +++ b/experimental/crash_triage/triage_crashes.sh @@ -5,7 +5,7 @@ # # Written and maintained by Michal Zalewski # -# Copyright 2013, 2014 Google Inc. All rights reserved. +# Copyright 2013, 2014, 2017 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. @@ -28,18 +28,16 @@ echo ulimit -v 100000 2>/dev/null ulimit -d 100000 2>/dev/null -if [ ! "$#" = "2" ]; then - echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary" 1>&2 - echo 1>&2 - echo "Note: the tested binary must accept input on stdin and require no additional" 1>&2 - echo "parameters. For more complex use cases, you need to edit this script." 1>&2 +if [ "$#" -lt "2" ]; then + echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2 echo 1>&2 exit 1 fi DIR="$1" BIN="$2" - +shift +shift if [ "$AFL_ALLOW_TMP" = "" ]; then @@ -85,11 +83,33 @@ for crash in $DIR/crashes/id:*; do id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2` sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2` + # Grab the args, converting @@ to $crash + + use_args="" + use_stdio=1 + + for a in $@; do + + if [ "$a" = "@@" ] ; then + args="$use_args $crash" + unset use_stdio + else + args="$use_args $a" + fi + + done + + # Strip the trailing space + use_args="${use_args# }" + echo "+++ ID $id, SIGNAL $sig +++" echo - $GDB --batch -q --ex "r <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0 MAX_AUTO_EXTRA) return; + if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || !__tokencap_out_file) + return; for (i = 0; i < len; i++) { diff --git a/qemu_mode/README.qemu b/qemu_mode/README.qemu index f9dce99..cf29088 100644 --- a/qemu_mode/README.qemu +++ b/qemu_mode/README.qemu @@ -21,7 +21,7 @@ The idea and much of the implementation comes from Andrew Griffiths. 2) How to use ------------- -The feature is implemented with a fairly simple patch to QEMU 2.3.0. The +The feature is implemented with a fairly simple patch to QEMU 2.10.0. The simplest way to build it is to run ./build_qemu_support.sh. The script will download, configure, and compile the QEMU binary for you. diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 7224671..827c93d 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -6,7 +6,7 @@ # Written by Andrew Griffiths and # Michal Zalewski # -# Copyright 2015, 2016 Google Inc. All rights reserved. +# Copyright 2015, 2016, 2017 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. @@ -22,8 +22,10 @@ # will be written to ../afl-qemu-trace. # -QEMU_URL="http://wiki.qemu-project.org/download/qemu-2.3.0.tar.bz2" -QEMU_SHA384="7a0f0c900f7e2048463cc32ff3e904965ab466c8428847400a0f2dcfe458108a68012c4fddb2a7e7c822b4fd1a49639b" + +VERSION="2.10.0" +QEMU_URL="http://download.qemu-project.org/qemu-${VERSION}.tar.xz" +QEMU_SHA384="68216c935487bc8c0596ac309e1e3ee75c2c4ce898aab796faa321db5740609ced365fedda025678d072d09ac8928105" echo "=================================================" echo "AFL binary-only instrumentation QEMU build script" @@ -89,7 +91,7 @@ CKSUM=`sha384sum -- "$ARCHIVE" 2>/dev/null | cut -d' ' -f1` if [ ! "$CKSUM" = "$QEMU_SHA384" ]; then - echo "[*] Downloading QEMU 2.3.0 from the web..." + echo "[*] Downloading QEMU ${VERSION} from the web..." rm -f "$ARCHIVE" wget -O "$ARCHIVE" -- "$QEMU_URL" || exit 1 @@ -110,32 +112,34 @@ fi echo "[*] Uncompressing archive (this will take a while)..." -rm -rf "qemu-2.3.0" || exit 1 +rm -rf "qemu-${VERSION}" || exit 1 tar xf "$ARCHIVE" || exit 1 echo "[+] Unpacking successful." -echo "[*] Applying patches..." - -patch -p0 pc == afl_entry_point) { \ + if(itb->pc == afl_entry_point) { \ afl_setup(); \ - afl_forkserver(env); \ + afl_forkserver(cpu); \ } \ - afl_maybe_log(tb->pc); \ + afl_maybe_log(itb->pc); \ } while (0) /* We use one additional file descriptor to relay "needs translation" @@ -81,16 +81,12 @@ static unsigned int afl_inst_rms = MAP_SIZE; /* Function declarations. */ static void afl_setup(void); -static void afl_forkserver(CPUArchState*); +static void afl_forkserver(CPUState*); static inline void afl_maybe_log(abi_ulong); -static void afl_wait_tsl(CPUArchState*, int); +static void afl_wait_tsl(CPUState*, int); static void afl_request_tsl(target_ulong, target_ulong, uint64_t); -static TranslationBlock *tb_find_slow(CPUArchState*, target_ulong, - target_ulong, uint64_t); - - /* Data structure passed around by the translate handlers: */ struct afl_tsl { @@ -99,12 +95,15 @@ struct afl_tsl { uint64_t flags; }; +/* Some forward decls: */ + +TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t); +static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int); /************************* * ACTUAL IMPLEMENTATION * *************************/ - /* Set up SHM region and initialize other stuff. */ static void afl_setup(void) { @@ -149,12 +148,18 @@ static void afl_setup(void) { } + /* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm + not entirely sure what is the cause. This disables that + behaviour, and seems to work alright? */ + + rcu_disable_atfork(); + } /* Fork server logic, invoked once we hit _start. */ -static void afl_forkserver(CPUArchState *env) { +static void afl_forkserver(CPUState *cpu) { static unsigned char tmp[4]; @@ -178,7 +183,7 @@ static void afl_forkserver(CPUArchState *env) { if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); - /* Establish a channel with child to grab translation commands. We'll + /* Establish a channel with child to grab translation commands. We'll read from t_fd[0], child will write to TSL_FD. */ if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); @@ -207,7 +212,7 @@ static void afl_forkserver(CPUArchState *env) { /* Collect translation requests until child dies and closes the pipe. */ - afl_wait_tsl(env, t_fd[0]); + afl_wait_tsl(cpu, t_fd[0]); /* Get and relay exit status to parent. */ @@ -269,13 +274,13 @@ static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) { } - /* This is the other side of the same channel. Since timeouts are handled by afl-fuzz simply killing the child, we can just wait until the pipe breaks. */ -static void afl_wait_tsl(CPUArchState *env, int fd) { +static void afl_wait_tsl(CPUState *cpu, int fd) { struct afl_tsl t; + TranslationBlock *tb; while (1) { @@ -284,11 +289,18 @@ static void afl_wait_tsl(CPUArchState *env, int fd) { if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) break; - tb_find_slow(env, t.pc, t.cs_base, t.flags); + tb = tb_htable_lookup(cpu, t.pc, t.cs_base, t.flags); + + if(!tb) { + mmap_lock(); + tb_lock(); + tb_gen_code(cpu, t.pc, t.cs_base, t.flags, 0); + mmap_unlock(); + tb_unlock(); + } } close(fd); } - diff --git a/qemu_mode/patches/cpu-exec.diff b/qemu_mode/patches/cpu-exec.diff index f7085cd..9c69d0c 100644 --- a/qemu_mode/patches/cpu-exec.diff +++ b/qemu_mode/patches/cpu-exec.diff @@ -1,33 +1,28 @@ ---- qemu-2.3.0/cpu-exec.c.orig 2014-12-09 14:45:40.000000000 +0000 -+++ qemu-2.3.0/cpu-exec.c 2015-02-20 22:07:02.966000000 +0000 -@@ -28,6 +28,8 @@ - #include "exec/memory-internal.h" - #include "qemu/rcu.h" - +--- qemu-2.10.0-rc3-clean/accel/tcg/cpu-exec.c 2017-08-15 11:39:41.000000000 -0700 ++++ qemu-2.10.0-rc3/accel/tcg/cpu-exec.c 2017-08-22 14:34:55.868730680 -0700 +@@ -36,6 +36,8 @@ + #include "sysemu/cpus.h" + #include "sysemu/replay.h" + +#include "../patches/afl-qemu-cpu-inl.h" + /* -icount align implementation. */ - + typedef struct SyncClocks { -@@ -296,8 +298,11 @@ - } - not_found: - /* if no translated code available, then translate it now */ +@@ -144,6 +146,8 @@ + int tb_exit; + uint8_t *tb_ptr = itb->tc_ptr; + ++ AFL_QEMU_CPU_SNIPPET2; + - tb = tb_gen_code(cpu, pc, cs_base, flags, 0); - -+ AFL_QEMU_CPU_SNIPPET1; -+ - found: - /* Move the last found TB to the head of the list */ - if (likely(*ptb1)) { -@@ -492,6 +497,9 @@ - next_tb = 0; - tcg_ctx.tb_ctx.tb_invalidated_flag = 0; - } -+ -+ AFL_QEMU_CPU_SNIPPET2; -+ - if (qemu_loglevel_mask(CPU_LOG_EXEC)) { - qemu_log("Trace %p [" TARGET_FMT_lx "] %s\n", - tb->tc_ptr, tb->pc, lookup_symbol(tb->pc)); + qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc, + "Trace %p [%d: " TARGET_FMT_lx "] %s\n", + itb->tc_ptr, cpu->cpu_index, itb->pc, +@@ -365,6 +369,7 @@ + if (!tb) { + /* if no translated code available, then translate it now */ + tb = tb_gen_code(cpu, pc, cs_base, flags, 0); ++ AFL_QEMU_CPU_SNIPPET1; + } + + mmap_unlock(); diff --git a/qemu_mode/patches/elfload.diff b/qemu_mode/patches/elfload.diff index 325c917..f4a53d6 100644 --- a/qemu_mode/patches/elfload.diff +++ b/qemu_mode/patches/elfload.diff @@ -1,6 +1,6 @@ ---- qemu-2.3.0/linux-user/elfload.c.orig 2014-12-09 14:45:42.000000000 +0000 -+++ qemu-2.3.0/linux-user/elfload.c 2015-01-28 02:51:23.719000000 +0000 -@@ -28,6 +28,8 @@ +--- qemu-2.10.0-rc3-clean/linux-user/elfload.c 2017-08-15 11:39:41.000000000 -0700 ++++ qemu-2.10.0-rc3/linux-user/elfload.c 2017-08-22 14:33:57.397127516 -0700 +@@ -20,6 +20,8 @@ #define ELF_OSABI ELFOSABI_SYSV @@ -9,7 +9,7 @@ /* from personality.h */ /* -@@ -1889,6 +1891,8 @@ +@@ -2085,6 +2087,8 @@ info->brk = 0; info->elf_flags = ehdr->e_flags; @@ -18,7 +18,7 @@ for (i = 0; i < ehdr->e_phnum; i++) { struct elf_phdr *eppnt = phdr + i; if (eppnt->p_type == PT_LOAD) { -@@ -1922,9 +1926,11 @@ +@@ -2118,9 +2122,11 @@ if (elf_prot & PROT_EXEC) { if (vaddr < info->start_code) { info->start_code = vaddr; diff --git a/qemu_mode/patches/syscall.diff b/qemu_mode/patches/syscall.diff index 75d3938..55b2914 100644 --- a/qemu_mode/patches/syscall.diff +++ b/qemu_mode/patches/syscall.diff @@ -1,25 +1,35 @@ ---- qemu-2.3.0/linux-user/syscall.c.orig 2014-12-09 14:45:43.000000000 +0000 -+++ qemu-2.3.0/linux-user/syscall.c 2015-03-27 06:33:00.736000000 +0000 -@@ -227,7 +227,21 @@ - _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) - _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) - #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) --_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) -+ +--- qemu-2.10.0-rc3-clean/linux-user/syscall.c 2017-08-15 11:39:41.000000000 -0700 ++++ qemu-2.10.0-rc3/linux-user/syscall.c 2017-08-22 14:34:03.193088186 -0700 +@@ -116,6 +116,8 @@ + + #include "qemu.h" + +extern unsigned int afl_forksrv_pid; + -+static int sys_tgkill(int tgid, int pid, int sig) { + #ifndef CLONE_IO + #define CLONE_IO 0x80000000 /* Clone io context */ + #endif +@@ -11688,8 +11690,21 @@ + break; + + case TARGET_NR_tgkill: +- ret = get_errno(safe_tgkill((int)arg1, (int)arg2, +- target_to_host_signal(arg3))); ++ ++ { ++ int pid = (int)arg1, ++ tgid = (int)arg2, ++ sig = (int)arg3; + -+ /* Workaround for -lpthread to make abort() work properly, without -+ killing the forkserver due to a prematurely cached PID. */ ++ /* Not entirely sure if the below is correct for all architectures. */ + -+ if (afl_forksrv_pid && afl_forksrv_pid == pid && sig == SIGABRT) -+ pid = tgid = getpid(); ++ if(afl_forksrv_pid && afl_forksrv_pid == pid && sig == SIGABRT) ++ pid = tgid = getpid(); + -+ return syscall(__NR_sys_tgkill, pid, tgid, sig); ++ ret = get_errno(safe_tgkill(pid, tgid, target_to_host_signal(sig))); + -+} ++ } + - #endif - #if defined(TARGET_NR_tkill) && defined(__NR_tkill) - _syscall2(int,sys_tkill,int,tid,int,sig) + break; + + #ifdef TARGET_NR_set_robust_list