From 5144d64301ff1509124a429588e034f705d103d1 Mon Sep 17 00:00:00 2001 From: Thomas HUET Date: Wed, 2 Mar 2016 23:04:46 +0100 Subject: [PATCH] 2.03b --- Makefile | 12 ++--- afl-analyze.c | 31 ++++++++--- afl-fuzz.c | 40 +++++++++++--- afl-showmap.c | 7 ++- afl-tmin.c | 31 ++++++++--- config.h | 2 +- debug.h | 2 +- docs/ChangeLog | 26 ++++++++- docs/INSTALL | 2 +- docs/README | 1 + docs/env_variables.txt | 10 +++- docs/sister_projects.txt | 9 ++++ docs/status_screen.txt | 20 ++++--- llvm_mode/Makefile | 29 ++++++---- llvm_mode/README.llvm | 28 +++++++++- llvm_mode/afl-clang-fast.c | 21 +++++++- llvm_mode/afl-llvm-pass.so.cc | 18 ++++--- llvm_mode/afl-llvm-rt.o.c | 80 +++++++++++++++++++++++++++- qemu_mode/patches/afl-qemu-cpu-inl.h | 12 ++--- 19 files changed, 313 insertions(+), 68 deletions(-) diff --git a/Makefile b/Makefile index 1c401fda..8416634b 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # # Written and maintained by Michal Zalewski # -# Copyright 2013, 2014, 2015 Google Inc. All rights reserved. +# Copyright 2013, 2014, 2015, 2016 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. @@ -14,7 +14,7 @@ # PROGNAME = afl -VERSION = 2.02b +VERSION = 2.03b PREFIX ?= /usr/local BIN_PATH = $(PREFIX)/bin @@ -46,18 +46,18 @@ COMM_HDR = alloc-inl.h config.h debug.h types.h all: test_x86 $(PROGS) afl-as test_build all_done -ifndef AFL_NOX86 +ifndef AFL_NO_X86 test_x86: @echo "[*] Checking for the ability to compile x86 code..." - @echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "You can still try using the LLVM or QEMU mode, but see docs/INSTALL first."; echo "To ignore this error, set AFL_NOX86=1."; echo; exit 1 ) + @echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "You can still try using the LLVM or QEMU mode, but see docs/INSTALL first."; echo "To ignore this error, set AFL_NO_X86=1."; echo; exit 1 ) @rm -f .test @echo "[+] Everything seems to be working, ready to compile." else test_x86: - @echo "[!] Note: skipping x86 compilation checks (AFL_NOX86 set)." + @echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)." endif @@ -84,7 +84,7 @@ afl-analyze: afl-analyze.c $(COMM_HDR) | test_x86 afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) -ifndef AFL_NOX86 +ifndef AFL_NO_X86 test_build: afl-gcc afl-as afl-showmap @echo "[*] Testing the CC wrapper and instrumentation output..." diff --git a/afl-analyze.c b/afl-analyze.c index ccd550a8..bf6248e2 100644 --- a/afl-analyze.c +++ b/afl-analyze.c @@ -677,22 +677,41 @@ static void set_up_environment(void) { x = getenv("ASAN_OPTIONS"); - if (x && !strstr(x, "abort_on_error=1")) - FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + if (x) { + + if (!strstr(x, "abort_on_error=1")) + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } x = getenv("MSAN_OPTIONS"); - if (x && !strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) - FATAL("Custom MSAN_OPTIONS set without exit_code=" - STRINGIFY(MSAN_ERROR) " - please fix!"); + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) + FATAL("Custom MSAN_OPTIONS set without exit_code=" + STRINGIFY(MSAN_ERROR) " - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "symbolize=0:" "allocator_may_return_null=1", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" "msan_track_origins=0", 0); + if (getenv("AFL_LD_PRELOAD")) + setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1); + } @@ -773,7 +792,7 @@ static void usage(u8* argv0) { "Required parameters:\n\n" - " -i file - input test case to be shrunk by the tool\n" + " -i file - input test case to be analyzed by the tool\n" "Execution control settings:\n\n" diff --git a/afl-fuzz.c b/afl-fuzz.c index 2d12b823..22e1ce5e 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -6,7 +6,7 @@ Forkserver design by Jann Horn - Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016 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. @@ -1934,12 +1934,14 @@ static void init_forkserver(char** argv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "symbolize=0:" "allocator_may_return_null=1", 0); /* MSAN is tricky, because it doesn't support abort_on_error=1 at this point. So, we do this in a very hacky way. */ setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" "msan_track_origins=0", 0); execv(target_path, argv); @@ -2197,9 +2199,11 @@ static u8 run_target(char** argv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "symbolize=0:" "allocator_may_return_null=1", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" "msan_track_origins=0", 0); execv(target_path, argv); @@ -7155,14 +7159,28 @@ static void handle_resize(int sig) { static void check_asan_opts(void) { u8* x = getenv("ASAN_OPTIONS"); - if (x && !strstr(x, "abort_on_error=1")) - FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + if (x) { + + if (!strstr(x, "abort_on_error=1")) + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } x = getenv("MSAN_OPTIONS"); - if (x && !strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) - FATAL("Custom MSAN_OPTIONS set without exit_code=" - STRINGIFY(MSAN_ERROR) " - please fix!"); + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) + FATAL("Custom MSAN_OPTIONS set without exit_code=" + STRINGIFY(MSAN_ERROR) " - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } } @@ -7365,6 +7383,7 @@ int main(int argc, char** argv) { u32 sync_interval_cnt = 0, seek_to; u8 *extras_dir = 0; u8 mem_limit_given = 0; + u8 exit_1 = !!getenv("AFL_BENCH_JUST_ONE"); char** use_argv; @@ -7553,6 +7572,9 @@ int main(int argc, char** argv) { if (dumb_mode == 2 && no_forkserver) FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); + if (getenv("AFL_LD_PRELOAD")) + setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1); + save_cmdline(argc, argv); fix_up_banner(argv[optind]); @@ -7661,6 +7683,8 @@ int main(int argc, char** argv) { } + if (!stop_soon && exit_1) stop_soon = 2; + if (stop_soon) break; queue_cur = queue_cur->next; @@ -7676,8 +7700,8 @@ int main(int argc, char** argv) { stop_fuzzing: - SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing %s +++\n" cRST, - stop_soon == 2 ? "ended via AFL_EXIT_WHEN_DONE" : "aborted by user"); + SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST, + stop_soon == 2 ? "programatically" : "by user"); /* Running for more than 30 minutes but still doing first cycle? */ diff --git a/afl-showmap.c b/afl-showmap.c index 2ecd1dc4..04dc7e09 100644 --- a/afl-showmap.c +++ b/afl-showmap.c @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016 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. @@ -332,11 +332,16 @@ static void set_up_environment(void) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "symbolize=0:" "allocator_may_return_null=1", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" "msan_track_origins=0", 0); + if (getenv("AFL_LD_PRELOAD")) + setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1); + } diff --git a/afl-tmin.c b/afl-tmin.c index d1abf0fc..24967ee3 100644 --- a/afl-tmin.c +++ b/afl-tmin.c @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2015 Google Inc. All rights reserved. + Copyright 2015, 2016 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. @@ -668,22 +668,41 @@ static void set_up_environment(void) { x = getenv("ASAN_OPTIONS"); - if (x && !strstr(x, "abort_on_error=1")) - FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + if (x) { + + if (!strstr(x, "abort_on_error=1")) + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } x = getenv("MSAN_OPTIONS"); - if (x && !strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) - FATAL("Custom MSAN_OPTIONS set without exit_code=" - STRINGIFY(MSAN_ERROR) " - please fix!"); + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) + FATAL("Custom MSAN_OPTIONS set without exit_code=" + STRINGIFY(MSAN_ERROR) " - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "symbolize=0:" "allocator_may_return_null=1", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" "msan_track_origins=0", 0); + if (getenv("AFL_LD_PRELOAD")) + setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1); + } diff --git a/config.h b/config.h index 4610f933..4405974a 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016 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. diff --git a/debug.h b/debug.h index 1bdfb6c3..a943a573 100644 --- a/debug.h +++ b/debug.h @@ -4,7 +4,7 @@ Written and maintained by Michal Zalewski - Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + Copyright 2013, 2014, 2015, 2016 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. diff --git a/docs/ChangeLog b/docs/ChangeLog index f4dcb5f4..308e68fa 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -13,9 +13,33 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . Not sure if you should upgrade? The lowest currently recommended version -is 1.92b. If you're stuck on an earlier release, it's strongly advisable +is 2.03b. If you're stuck on an earlier release, it's strongly advisable to get on with the times. +-------------- +Version 2.03b: +-------------- + + - Added experimental -fsanitize-coverage=trace-pc support that goes with + some recent additions to LLVM, as implemented by Kostya Serebryany. + Right now, this is cumbersome to use with common build systems, so + the mode remains undocumented. + + - Made several substantial improvements to better support non-standard + map sizes in LLVM mode. + + - Switched LLVM mode to thread-local execution tracing, which may offer + better results in some multithreaded apps. + + - Fixed a minor typo, reported by Heiko Eissfeldt. + + - Force-disabled symbolization for ASAN, as suggested by Christian Holler. + + - AFL_NOX86 renamed to AFL_NO_X86 for consistency. + + - Added AFL_LD_PRELOAD to allow LD_PRELOAD to be set for targets without + affecting AFL itself. Suggested by Daniel Godas-Lopez. + -------------- Version 2.02b: -------------- diff --git a/docs/INSTALL b/docs/INSTALL index 06844587..59e51b7c 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -110,7 +110,7 @@ leverage two other options: - The QEMU mode (see qemu_mode/README.qemu), which can be also used for fuzzing cross-platform binaries. -In both cases, you will need to set AFL_NOX86=1 before running make or gmake. +In both cases, you will need to set AFL_NO_X86=1 before running make or gmake. 5) Solaris on x86 ----------------- diff --git a/docs/README b/docs/README index 47be3d9d..53888c03 100644 --- a/docs/README +++ b/docs/README @@ -433,6 +433,7 @@ bug reports, or patches from: Jacek Wielemborek Leo Barnes Jeremy Barnes Jeff Trull Guillaume Endignoux ilovezfs + Daniel Godas-Lopez Thank you! diff --git a/docs/env_variables.txt b/docs/env_variables.txt index 73b31a43..ebb629c7 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -139,9 +139,15 @@ checks or alter some of the more exotic semantics of the tool: - In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace. + - Setting AFL_LD_PRELOAD causes AFL to set LD_PRELOAD for the target binary + without disrupting the afl-fuzz process itself. + - If you are Jakub, you may need AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES. Others need not apply. + - Benchmarking only: AFL_BENCH_JUST_ONE causes the fuzzer to exit after + processing the first queue entry. + 4) Settings for afl-qemu-trace ------------------------------ @@ -192,11 +198,13 @@ optimal values if not already present in the environment: abort_on_error=1 detect_leaks=0 + symbolize=0 allocator_may_return_null=1 If you want to set your own options, be sure to include abort_on_error=1 - otherwise, the fuzzer will not be able to detect crashes in the tested - app. + app. Similarly, include symbolize=0, since without it, AFL may have + difficulty telling crashes and hangs apart. - In the same vein, by default, MSAN_OPTIONS are set to: diff --git a/docs/sister_projects.txt b/docs/sister_projects.txt index 6d272c2f..680b421f 100644 --- a/docs/sister_projects.txt +++ b/docs/sister_projects.txt @@ -240,3 +240,12 @@ Fuzzer shell for SQLite (Richard Hipp) http://www.sqlite.org/src/artifact/9e7e273da2030371 +Support for Python mutation modules (Christian Holler) +------------------------------------------------------ + + https://github.com/choller/afl/blob/master/docs/mozilla/python_modules.txt + +Support for selective instrumentation (Christian Holler) +-------------------------------------------------------- + + https://github.com/choller/afl/blob/master/docs/mozilla/partial_instrumentation.txt diff --git a/docs/status_screen.txt b/docs/status_screen.txt index 45e3069f..b1dd1dea 100644 --- a/docs/status_screen.txt +++ b/docs/status_screen.txt @@ -297,12 +297,6 @@ explanations for variable behavior of the tested program: - Use of uninitialized memory in conjunction with some intrinsic sources of entropy in the tested binary. This can be indicative of a security bug. - - Multiple threads executing at once in semi-random order. Not a big deal, - but to avoid hiccups, it's best to restrict instrumented programs to a - single thread. Check compile-time options or run-time flags. For example, - for ImageMagick, you can try --without-threads --disable-openmp; for - ffmpeg, look for --disable-pthreads instead. - - Attempts to create files that were already created during previous runs, or otherwise interact with some form of persistent state. This is harmless, but you may want to instruct the targeted program to write to stdout or to @@ -315,6 +309,20 @@ explanations for variable behavior of the tested program: select random(); + - Multiple threads executing at once in semi-random order. This is usually + just a nuisance, but if the number of variable paths is very high, try the + following options: + + - Use afl-clang-fast from llvm_mode/ - it uses a thread-local tracking + model that is less prone to concurrency issues, + + - See if the target can be compiled or run without threads. Common + ./configure options include --without-threads, --disable-pthreads, or + --disable-openmp. + + - Replace pthreads with GNU Pth (https://www.gnu.org/software/pth/), which + allows you to use a deterministic scheduler. + Less likely causes may include running out of disk space, SHM handles, or other globally limited resources. diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 93690a39..f5df16a8 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -7,7 +7,7 @@ # # LLVM integration design comes from Laszlo Szekeres. # -# Copyright 2015 Google Inc. All rights reserved. +# Copyright 2015, 2016 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. @@ -27,11 +27,14 @@ LLVM_CONFIG ?= llvm-config CFLAGS ?= -O3 -funroll-loops CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ - -DVERSION=\"$(VERSION)\" + -DVERSION=\"$(VERSION)\" +ifdef AFL_TRACE_PC + CFLAGS += -DUSE_TRACE_PC=1 +endif CXXFLAGS ?= -O3 -funroll-loops CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ - -DVERSION=\"$(VERSION)\" + -DVERSION=\"$(VERSION)\" -Wno-variadic-macros CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fpic $(CXXFLAGS) CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) @@ -39,9 +42,7 @@ 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 - + CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress endif # We were using llvm-config --bindir to get the location of clang, but @@ -49,19 +50,25 @@ endif # probably better. ifeq "$(origin CC)" "default" - -CC = clang -CXX = clang++ - + CC = clang + CXX = clang++ endif -PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-rt.o +ifndef AFL_TRACE_PC + PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-rt.o +else + PROGS = ../afl-clang-fast ../afl-llvm-rt.o +endif all: test_deps $(PROGS) test_build all_done test_deps: +ifndef AFL_TRACE_PC @echo "[*] Checking for working 'llvm-config'..." @which $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 ) +else + @echo "[!] Note: using -fsanitize=trace-pc mode (this will fail with older LLVM)." +endif @echo "[*] Checking for working '$(CC)'..." @which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 ) @echo "[*] Checking for '../afl-showmap'..." diff --git a/llvm_mode/README.llvm b/llvm_mode/README.llvm index 63f99f19..549002e1 100644 --- a/llvm_mode/README.llvm +++ b/llvm_mode/README.llvm @@ -22,7 +22,9 @@ several interesting properties: - The instrumentation is CPU-independent. At least in principle, you should be able to rely on it to fuzz programs on non-x86 architectures (after - building afl-fuzz with AFL_NOX86=1). + building afl-fuzz with AFL_NO_X86=1). + + - The instrumentation can cope a bit better with multi-threaded targets. - Because the feature relies on the internals of LLVM, it is clang-specific and will *not* work with GCC. @@ -166,3 +168,27 @@ 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. + +6) Bonus feature #3: new 'trace-pc' mode +---------------------------------------- + +Recent versions of LLVM are shipping with a built-in execution tracing feature +that is fairly usable for AFL, without the need to post-process the assembly +or install any compiler plugins. See: + + http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs + +As of this writing, the feature is only available on SVN trunk, and is yet to +make it to an official release of LLVM. Nevertheless, if you have a +sufficiently recent compiler and want to give it a try, build afl-clang-fast +this way: + + AFL_TRACE_PC=1 make clean all + +Since a form of 'trace-pc' is also supported in GCC, this mode may become a +longer-term solution to all our needs. + +Note that this mode supports AFL_INST_RATIO at run time, not at compilation +time. This is somewhat similar to the behavior of the QEMU mode. Because of +the need to support it at run time, the mode is also a tad slower than the +plugin-based approach. diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index f229478f..a0458c19 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -7,7 +7,7 @@ LLVM integration design comes from Laszlo Szekeres. - Copyright 2015 Google Inc. All rights reserved. + Copyright 2015, 2016 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. @@ -112,10 +112,22 @@ static void edit_params(u32 argc, char** argv) { cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; } + /* There are two ways to compile afl-clang-fast. In the traditional mode, we + use afl-llvm-pass.so to inject instrumentation. In the experimental + 'trace-pc' mode, we use native LLVM instrumentation callbacks instead. + The latter is a very recent addition - see: + + http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs */ + +#ifdef USE_TRACE_PC + cc_params[cc_par_cnt++] = "-fsanitize-coverage=bb,indirect-calls,trace-pc"; +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); +#endif /* ^USE_TRACE_PC */ + cc_params[cc_par_cnt++] = "-Qunused-arguments"; while (--argc) { @@ -168,6 +180,13 @@ static void edit_params(u32 argc, char** argv) { } +#ifdef USE_TRACE_PC + + if (getenv("AFL_INST_RATIO")) + FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'."); + +#endif /* USE_TRACE_PC */ + if (!getenv("AFL_DONT_OPTIMIZE")) { cc_params[cc_par_cnt++] = "-g"; diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 321dd0c2..84dcb84a 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -8,7 +8,7 @@ LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted from afl-as.c are Michal's fault. - Copyright 2015 Google Inc. All rights reserved. + Copyright 2015, 2016 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. @@ -66,8 +66,7 @@ bool AFLCoverage::runOnModule(Module &M) { LLVMContext &C = M.getContext(); IntegerType *Int8Ty = IntegerType::getInt8Ty(C); - IntegerType *Int16Ty = IntegerType::getInt16Ty(C); - IntegerType *Int64Ty = IntegerType::getInt64Ty(C); + IntegerType *Int32Ty = IntegerType::getInt32Ty(C); /* Show a banner */ @@ -92,14 +91,16 @@ bool AFLCoverage::runOnModule(Module &M) { } - /* Get globals for the SHM region and the previous location. */ + /* Get globals for the SHM region and the previous location. Note that + __afl_prev_loc is thread-local. */ GlobalVariable *AFLMapPtr = new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); GlobalVariable *AFLPrevLoc = new GlobalVariable( - M, Int16Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", + 0, GlobalValue::GeneralDynamicTLSModel, 0, false); /* Instrument all the things! */ @@ -116,13 +117,14 @@ bool AFLCoverage::runOnModule(Module &M) { /* Make up cur_loc */ unsigned int cur_loc = R(MAP_SIZE); - ConstantInt *CurLoc = ConstantInt::get(Int64Ty, cur_loc); + + ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc); /* Load prev_loc */ LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt64Ty()); + Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); /* Load SHM pointer */ @@ -142,7 +144,7 @@ bool AFLCoverage::runOnModule(Module &M) { /* Set prev_loc to cur_loc >> 1 */ StoreInst *Store = - IRB.CreateStore(ConstantInt::get(Int16Ty, cur_loc >> 1), AFLPrevLoc); + IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc); Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); inst_blocks++; diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 03e2afe0..2d8a89ae 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -7,7 +7,7 @@ LLVM integration design comes from Laszlo Szekeres. - Copyright 2015 Google Inc. All rights reserved. + Copyright 2015, 2016 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,6 +22,7 @@ #include "../config.h" #include "../types.h" +#include #include #include #include @@ -39,7 +40,8 @@ u8 __afl_area_initial[MAP_SIZE]; u8* __afl_area_ptr = __afl_area_initial; -u16 __afl_prev_loc; + +__thread u32 __afl_prev_loc; /* Running in persistent mode? */ @@ -214,3 +216,77 @@ __attribute__((constructor(0))) void __afl_auto_init(void) { } +/********************************************* + * Support for -fsanitize-coverage=trace-pc. * + *********************************************/ + +static u32 inst_ratio_scaled = MIN(4096, MAP_SIZE); + + +/* The first function is called on every basic block. We use the return address + instead of a randomly-generated token (because LLVM is not giving us one). + Since ASLR may make addresses vary across runs, we use only the last 12 + bits, which should be stable within a given binary. + + Since MAP_SIZE is usually larger than 12 bits, we "pad" it by combining + left-shifted __afl_prev_loc. This gives us a theoretical maximum of 24 + bits (but basic blocks might be aligned, which reduces this number + somewhat). */ + +void __sanitizer_cov_trace_pc(void) { + + u32 cur = ((u32)__builtin_return_address(0)) & MIN(4095, MAP_SIZE - 1); + + if (cur > inst_ratio_scaled) return; + + __afl_area_ptr[cur ^ __afl_prev_loc]++; + +#if MAP_SIZE_POW2 > 12 + __afl_prev_loc = cur << (MAP_SIZE_POW2 - 12); +#else + __afl_prev_loc = cur >> 1; +#endif /* ^MAP_SIZE_POW2 > 12 */ + +} + + +/* Same deal, but for indirect calls. */ + +void __sanitizer_cov_trace_pc_indir(void* dummy) { + + u32 cur = ((u32)__builtin_return_address(0)) & MIN(4095, MAP_SIZE - 1); + + if (cur > inst_ratio_scaled) return; + + __afl_area_ptr[cur ^ __afl_prev_loc]++; + +#if MAP_SIZE_POW2 > 12 + __afl_prev_loc = cur << (MAP_SIZE_POW2 - 12); +#else + __afl_prev_loc = cur >> 1; +#endif /* ^MAP_SIZE_POW2 > 12 */ + +} + + +/* Init callback. Unfortunately, LLVM does not support compile-time + instrumentation density scaling, at least not just yet - so the runtime + inst_ratio stuff slows us down :-( */ + +void __sanitizer_cov_module_init(void) { + + u8* x = getenv("AFL_INST_RATIO"); + + if (!x) return; + + inst_ratio_scaled = atoi(x); + + if (!inst_ratio_scaled || inst_ratio_scaled > 100) { + fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); + abort(); + } + + inst_ratio_scaled = inst_ratio_scaled * MIN(4096, MAP_SIZE) / 100; + +} + diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index de5613c4..eaa0e67b 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -7,7 +7,7 @@ Idea & design very much by Andrew Griffiths. - Copyright 2015 Google Inc. All rights reserved. + Copyright 2015, 2016 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. @@ -223,7 +223,7 @@ static void afl_forkserver(CPUArchState *env) { static inline void afl_maybe_log(abi_ulong cur_loc) { - static abi_ulong prev_loc; + static __thread abi_ulong prev_loc; /* Optimize for cur_loc > afl_end_code, which is the most likely case on Linux systems. */ @@ -231,11 +231,9 @@ static inline void afl_maybe_log(abi_ulong cur_loc) { if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) return; - /* Looks like QEMU always maps to fixed locations, so we can skip this: - cur_loc -= afl_start_code; */ - - /* Instruction addresses may be aligned. Let's mangle the value to get - something quasi-uniform. */ + /* Looks like QEMU always maps to fixed locations, so ASAN is not a + concern. Phew. But instruction addresses may be aligned. Let's mangle + the value to get something quasi-uniform. */ cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc &= MAP_SIZE - 1;