From d9ff84e39ecad47deec8808ea127fd90d9f5e8ef Mon Sep 17 00:00:00 2001 From: Heiko Eißfeldt Date: Sun, 30 Jun 2019 10:06:20 +0200 Subject: Refactor to use an alternative method for shared memory. If USEMMAP is defined, the shared memory segment is created/attached etc. now by shm_open() and mmap(). This API is hopefully more often available (at least for iOS). In order to reduce code duplication I have added new files sharedmem.[ch] which now encapsulate the shared memory method. This is based on the work of Proteas to support iOS fuzzing (thanks). https://github.com/Proteas/afl-ios/commit/866af8ad1cb230d5d753b546380a4af1e55d6946 Currently this is in an experimental status yet. Please report whether this variant works on 32 and 64 bit and on the supported platforms. This branch enables USEMMAP and has been tested on Linux. There is no auto detection for the mmap API yet. --- llvm_mode/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'llvm_mode/Makefile') diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 6b277536..0cb2e1c5 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -33,7 +33,7 @@ endif 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)\" -DUSEMMAP=1 -lrt ifdef AFL_TRACE_PC CFLAGS += -DUSE_TRACE_PC=1 endif -- cgit 1.4.1 From 37a379f959aecc465e79197c7adafa42ff5702d9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 2 Jul 2019 00:26:27 +0200 Subject: Makefile magic for llvm_mode --- Makefile | 31 ++++++++++++++++++++++--------- llvm_mode/Makefile | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 13 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index b051b497..2075b90f 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 # +# For Heiko: +#TEST_MMAP=1 + PROGNAME = afl VERSION = $(shell grep '^\#define VERSION ' config.h | cut -d '"' -f2) @@ -46,6 +49,7 @@ endif COMM_HDR = alloc-inl.h config.h debug.h types.h + ifeq "$(shell echo '\#include XXXvoid main() {}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 && echo 1 || echo 0 )" "1" PYTHON_OK=1 PYFLAGS=-DUSE_PYTHON -I$(PYTHON_INCLUDE) -lpython2.7 @@ -54,12 +58,19 @@ else PYFLAGS= endif + ifeq "$(shell echo '\#include XXX\#include XXX\#include XXXvoid main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, NULL);}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test2 && echo 1 || echo 0 )" "1" - SHM_OK=1 + SHMAT_OK=1 +else + SHMAT_OK=0 + CFLAGS+=-DUSEMMAP=1 + LDFLAGS+=-Wno-deprecated-declarations +endif + +ifeq "$(TEST_MMAP)" "1" + SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 LDFLAGS+=-Wno-deprecated-declarations -else - SHM_OK=0 endif @@ -81,16 +92,16 @@ test_x86: endif -ifeq "$(SHM_OK)" "1" +ifeq "$(SHMAT_OK)" "1" test_shm: - @rm -f .test2 2> /dev/null - @echo "[+] shmem seems to be working." + @echo "[+] shmat seems to be working." + @rm -f .test2 else test_shm: - @echo "[-] shmem seems not to be working, switchig to mmap implementation" + @echo "[-] shmat seems not to be working, switchig to mmap implementation" endif @@ -138,6 +149,7 @@ afl-analyze: afl-analyze.c sharedmem.o $(COMM_HDR) | test_x86 afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) + ifndef AFL_NO_X86 test_build: afl-gcc afl-as afl-showmap @@ -156,11 +168,12 @@ test_build: afl-gcc afl-as afl-showmap endif + all_done: test_build @if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi @echo "[+] All done! Be sure to review the README - it's pretty short and useful." -ifeq "$(SHM_OK)" "0" - @echo "[!] shmem isn't working on your platform - compile every target with -lrt:" +ifeq "$(SHMAT_OK)" "0" + @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-gcc CXX=afl-g++ ./configure" endif @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 0cb2e1c5..9f3cd010 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -16,6 +16,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 # +# For Heiko: +#TEST_MMAP=1 + PREFIX ?= /usr/local HELPER_PATH = $(PREFIX)/lib/afl BIN_PATH = $(PREFIX)/bin @@ -33,7 +36,7 @@ endif CFLAGS ?= -O3 -funroll-loops CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ - -DVERSION=\"$(VERSION)\" -DUSEMMAP=1 -lrt + -DVERSION=\"$(VERSION)\" ifdef AFL_TRACE_PC CFLAGS += -DUSE_TRACE_PC=1 endif @@ -45,12 +48,26 @@ CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS) CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) -# User teor2345 reports that this is required to make things work on MacOS X. +# 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 + +ifeq "$(shell echo '\#include XXX\#include XXX\#include XXXvoid main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, NULL);}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test2 && echo 1 || echo 0 )" "1" + SHMAT_OK=1 +else + SHMAT_OK=0 + CFLAGS+=-DUSEMMAP=1 +endif + +ifeq "$(TEST_MMAP)" "1" + SHMAT_OK=0 + CFLAGS+=-DUSEMMAP=1 +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. @@ -66,7 +83,22 @@ else PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so endif -all: test_deps $(PROGS) test_build all_done +all: test_deps test_shm $(PROGS) test_build all_done + + +ifeq "$(SHMAT_OK)" "1" + +test_shm: + @echo "[+] shmat seems to be working." + @rm -f .test2 + +else + +test_shm: + @echo "[-] shmat seems not to be working, switchig to mmap implementation" + +endif + test_deps: ifndef AFL_TRACE_PC @@ -119,9 +151,13 @@ test_build: $(PROGS) all_done: test_build @echo "[+] All done! You can now use '../afl-clang-fast' to compile programs." +ifeq "$(SHMAT_OK)" "0" + @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" + @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-clang-fast CXX=afl-clang-fast++ ./configure" +endif .NOTPARALLEL: clean clean: - rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 + rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 rm -f $(PROGS) ../afl-clang-fast++ -- cgit 1.4.1 From cc48f4499a6b4d646c19b99c0905324161eb03ed Mon Sep 17 00:00:00 2001 From: Heiko Eissfeldt Date: Tue, 2 Jul 2019 20:20:07 +0200 Subject: add librt under NetBSD --- Makefile | 4 ++++ llvm_mode/Makefile | 3 +++ 2 files changed, 7 insertions(+) (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index 2075b90f..7acdd049 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,10 @@ ifneq "$(filter Linux GNU%,$(shell uname))" "" LDFLAGS += -ldl -lrt endif +ifeq "$(shell uname)" "NetBSD" + LDFLAGS += -lrt +endif + ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" TEST_CC = afl-gcc else diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 9f3cd010..e2ed07d6 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -54,6 +54,9 @@ ifeq "$(shell uname)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress endif +ifeq "$(shell uname)" "NetBSD" + LDFLAGS += -lrt +endif ifeq "$(shell echo '\#include XXX\#include XXX\#include XXXvoid main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, NULL);}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test2 && echo 1 || echo 0 )" "1" SHMAT_OK=1 -- cgit 1.4.1 From b57b2073acf85e985f513a12d8aae725f8942689 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 3 Jul 2019 12:05:58 +0200 Subject: LAF_... -> AFL_LLVM_LAF_... --- docs/ChangeLog | 2 ++ docs/env_variables.txt | 6 +++--- llvm_mode/Makefile | 2 +- llvm_mode/README.laf-intel | 8 ++++---- llvm_mode/afl-clang-fast.c | 6 +++--- llvm_mode/split-compares-pass.so.cc | 2 ++ 6 files changed, 15 insertions(+), 11 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/docs/ChangeLog b/docs/ChangeLog index 0d730118..b758b211 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -30,6 +30,8 @@ Version ++2.52d (tbd): - added a -s seed switch to allow afl run with a fixed initial seed that is not updated. this is good for performance and path discovery tests as the random numbers are deterministic then + - llvm_mode LAF_... env variables can now be specified as AFL_LLVM_LAF_... + that is longer but in line with other llvm specific env vars - ... your idea or patch? diff --git a/docs/env_variables.txt b/docs/env_variables.txt index f5db3b4f..2a824766 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -89,11 +89,11 @@ Then there are a few specific features that are only available in llvm_mode: This great feature will split compares to series of single byte comparisons to allow afl-fuzz to find otherwise rather impossible paths. - - Setting LAF_SPLIT_SWITCHES will split switch()es + - Setting AFL_LLVM_LAF_SPLIT_SWITCHES will split switch()es - - Setting LAF_TRANSFORM_COMPARES will split string compare functions + - Setting AFL_LLVM_LAF_TRANSFORM_COMPARES will split string compare functions - - Setting LAF_SPLIT_COMPARES will split > 8 bit CMP instructions + - Setting AFL_LLVM_LAF_SPLIT_COMPARES will split > 8 bit CMP instructions See llvm_mode/README.laf-intel for more information. diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 6b277536..3304e62d 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -110,7 +110,7 @@ endif test_build: $(PROGS) @echo "[*] Testing the CC wrapper and instrumentation output..." - unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) LAF_SPLIT_SWITCHES=1 LAF_TRANSFORM_COMPARES=1 LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) + unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) echo 0 | ../afl-showmap -m none -q -o .test-instr0 ./test-instr echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr diff --git a/llvm_mode/README.laf-intel b/llvm_mode/README.laf-intel index 891ab5fd..340216c3 100644 --- a/llvm_mode/README.laf-intel +++ b/llvm_mode/README.laf-intel @@ -8,13 +8,13 @@ compile the target project. The following options exist: -export LAF_SPLIT_SWITCHES=1 Enables the split-switches pass. +export AFL_LLVM_LAF_SPLIT_SWITCHES=1 Enables the split-switches pass. -export LAF_TRANSFORM_COMPARES=1 Enables the transform-compares pass +export AFL_LLVM_LAF_TRANSFORM_COMPARES=1 Enables the transform-compares pass (strcmp, memcmp, strncmp, strcasecmp, strncasecmp). -export LAF_SPLIT_COMPARES=1 Enables the split-compares pass. +export AFL_LLVM_LAF_SPLIT_COMPARES=1 Enables the split-compares pass. By default it will split all compares with a bit width <= 64 bits. You can change this behaviour by setting - export LAF_SPLIT_COMPARES_BITW=. + export AFL_LLVM_LAF_SPLIT_COMPARES_BITW=. diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 1e2e04ea..5bc4ae8c 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -120,21 +120,21 @@ static void edit_params(u32 argc, char** argv) { http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */ // laf - if (getenv("LAF_SPLIT_SWITCHES")) { + if (getenv("LAF_SPLIT_SWITCHES")||getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) { 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/split-switches-pass.so", obj_path); } - if (getenv("LAF_TRANSFORM_COMPARES")) { + if (getenv("LAF_TRANSFORM_COMPARES")||getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { 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/compare-transform-pass.so", obj_path); } - if (getenv("LAF_SPLIT_COMPARES")) { + if (getenv("LAF_SPLIT_COMPARES")||getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc index 25ccb3b4..2ea73aaa 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/llvm_mode/split-compares-pass.so.cc @@ -477,6 +477,8 @@ bool SplitComparesTransform::runOnModule(Module &M) { int bitw = 64; char* bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); + if (!bitw_env) + bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { bitw = atoi(bitw_env); } -- cgit 1.4.1 From aaa810c64a7d54d21df6c74c3f7b77fb06d273fe Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 3 Jul 2019 12:11:02 +0200 Subject: add -lrt with afl-gcc/clang automatically in mmap mode --- Makefile | 8 ++++---- afl-gcc.c | 4 ++++ llvm_mode/Makefile | 8 ++++---- llvm_mode/afl-clang-fast.c | 4 ++++ 4 files changed, 16 insertions(+), 8 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index 7acdd049..14b5ce0e 100644 --- a/Makefile +++ b/Makefile @@ -176,10 +176,10 @@ endif all_done: test_build @if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi @echo "[+] All done! Be sure to review the README - it's pretty short and useful." -ifeq "$(SHMAT_OK)" "0" - @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" - @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-gcc CXX=afl-g++ ./configure" -endif +#ifeq "$(SHMAT_OK)" "0" +# @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" +# @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-gcc CXX=afl-g++ ./configure" +#endif @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.txt for advice.\033[0m\n" 2>/dev/null diff --git a/afl-gcc.c b/afl-gcc.c index 8d3988c7..467a9bc1 100644 --- a/afl-gcc.c +++ b/afl-gcc.c @@ -252,6 +252,10 @@ static void edit_params(u32 argc, char** argv) { } +#ifdef USEMMAP + cc_params[cc_par_cnt++] = "-lrt"; +#endif + if (!getenv("AFL_DONT_OPTIMIZE")) { #if defined(__FreeBSD__) && defined(__x86_64__) diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index e2ed07d6..d3e0c739 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -154,10 +154,10 @@ test_build: $(PROGS) all_done: test_build @echo "[+] All done! You can now use '../afl-clang-fast' to compile programs." -ifeq "$(SHMAT_OK)" "0" - @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" - @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-clang-fast CXX=afl-clang-fast++ ./configure" -endif +#ifeq "$(SHMAT_OK)" "0" +# @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" +# @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-clang-fast CXX=afl-clang-fast++ ./configure" +#endif .NOTPARALLEL: clean diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 1e2e04ea..366389b4 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -246,6 +246,10 @@ static void edit_params(u32 argc, char** argv) { } +#ifdef USEMMAP + cc_params[cc_par_cnt++] = "-lrt"; +#endif + cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; -- cgit 1.4.1 From 7f6aaa53147afd4feb549214f49d0f5f69e4af6c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 5 Jul 2019 11:28:08 +0200 Subject: final touches --- docs/ChangeLog | 2 + docs/env_variables.txt | 7 +++- llvm_mode/Makefile | 6 +++ llvm_mode/README.neverzero | 22 +++++++++++ llvm_mode/afl-llvm-pass.so.cc | 91 ++++++++++++++++++------------------------- 5 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 llvm_mode/README.neverzero (limited to 'llvm_mode/Makefile') diff --git a/docs/ChangeLog b/docs/ChangeLog index 73c69196..a533de05 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -17,6 +17,8 @@ sending a mail to . Version ++2.52d (tbd): ----------------------------- + - added never zero counters for afl-gcc and optional (because of an + optimization issue in llvm < 9) for llvm_mode (AFL_LLVM_NEVER_ZERO=1) - added whitelist support for llvm_mode via AFL_LLVM_WHITELIST to allow only to instrument what is actually interesting. Gives more speed and less map pollution (originally by choller@mozilla) diff --git a/docs/env_variables.txt b/docs/env_variables.txt index 725dc82e..f8c6c86a 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -108,8 +108,11 @@ Then there are a few specific features that are only available in llvm_mode: OTHER ===== - - Setting AFL_NZERO_COUNTS=1 during compilation will use counters - that skip zero on overflow. + - Setting export AFL_LLVM_NOT_ZERO=1 during compilation will use counters + that skip zero on overflow. This is the default for llvm >= 9, + however for llvm versions below that this will increase an unnecessary + slowdown due a performance issue that is only fixed in llvm 9+. + This feature increases path discovery by a little bit. Note that AFL_INST_RATIO will behave a bit differently than for afl-gcc, because functions are *not* instrumented unconditionally - so low values diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 6b277536..76de10c0 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -25,11 +25,17 @@ VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) LLVM_CONFIG ?= llvm-config #LLVM_OK = $(shell $(LLVM_CONFIG) --version | egrep -q '^[5-6]' && echo 0 || echo 1 ) LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version | egrep -q '^9|3.0' && echo 1 || echo 0 ) +LLVM_MAJOR = ($shell $(LLVM_CONFIG) --version | sed 's/\..*//') ifeq "$(LLVM_UNSUPPORTED)" "1" $(warn llvm_mode only supports versions 3.8.0 up to 8.x ) endif +# this is not visible yet: +ifeq "$(LLVM_MAJOR)" "9" + $(info llvm_mode deteted llvm 9, enabling neverZero implementation) +endif + CFLAGS ?= -O3 -funroll-loops CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ diff --git a/llvm_mode/README.neverzero b/llvm_mode/README.neverzero new file mode 100644 index 00000000..ef873acb --- /dev/null +++ b/llvm_mode/README.neverzero @@ -0,0 +1,22 @@ +Usage +===== + +In larger, complex or reiterative programs the map that collects the edge pairs +can easily fill up and wrap. +This is not that much of an issue - unless by chance it wraps just to a 0 +when the program execution ends. +In this case afl-fuzz is not able to see that the pair has been accessed and +will ignore it. + +NeverZero prevents this behaviour. If a counter wraps, it jumps over the 0 +directly to a 1. This improves path discovery (by a very little amount) +at a very little cost (one instruction per edge). + +This is implemented in afl-gcc, however for llvm_mode this is optional if +the llvm version is below 9 - as there is a perfomance bug that is only fixed +in version 9 and onwards. + +If you want to enable this for llvm < 9 then set + +export AFL_LLVM_NOT_ZERO=1 + diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 176692e3..cfeff968 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -118,7 +118,9 @@ bool AFLCoverage::runOnModule(Module &M) { } - char* neverZero_counters_str = getenv("AFL_NZERO_COUNTS"); +#if LLVM_VERSION_MAJOR < 9 + char* neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); +#endif /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ @@ -236,75 +238,56 @@ bool AFLCoverage::runOnModule(Module &M) { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *Incr; - // if (neverZero_counters_str == NULL || neverZero_counters_str[0] != '4') - Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1)); - - if (neverZero_counters_str != NULL) { - /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter - */ - - // Solution #1 - creates - //mov ecx,edx - //add cl,0x1 - //adc dl,0x1 -/* - if (neverZero_counters_str[0] == '1') { - CallInst *AddOv = IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter, ConstantInt::get(Int8Ty, 1)); - AddOv->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *SumWithOverflowBit = AddOv; - Incr = IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum - IRB.CreateZExt( // convert from one bit type to 8 bits type - IRB.CreateExtractValue(SumWithOverflowBit, 1), // overflow - Int8Ty)); - - // Solution #2 - creates the same code as #1 + Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1)); + +#if LLVM_VERSION_MAJOR < 9 + if (neverZero_counters_str != NULL) { // with llvm 9 we make this the default as the bug in llvm is then fixed +#endif + /* hexcoder: Realize a counter that skips zero during overflow. + * Once this counter reaches its maximum value, it next increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter + */ +/* // we keep the old solutions just in case + // Solution #1 + if (neverZero_counters_str[0] == '1') { + CallInst *AddOv = IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter, ConstantInt::get(Int8Ty, 1)); + AddOv->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + Value *SumWithOverflowBit = AddOv; + Incr = IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum + IRB.CreateZExt( // convert from one bit type to 8 bits type + IRB.CreateExtractValue(SumWithOverflowBit, 1), // overflow + Int8Ty)); + // Solution #2 } else if (neverZero_counters_str[0] == '2') { - auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1)); - Incr = IRB.CreateAdd(Incr, cf); - - // Solution #3 - creates - //add cl,0x1 - //cmp cl,0x1 - //adc cl,0x0 - } else if (neverZero_counters_str[0] == '3') { - auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0)); - Incr = IRB.CreateAdd(Incr, cf); - // Solution #4 - creates - // cmp dl, $0xff - // sete cl - // add dl,cl - // add dl,0x01 - } else if (neverZero_counters_str[0] == '4') { auto cf = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, 255)); Value *HowMuch = IRB.CreateAdd(ConstantInt::get(Int8Ty, 1), cf); Incr = IRB.CreateAdd(Counter, HowMuch); - - } else if (neverZero_counters_str[0] == '5') { + // Solution #3 + } else if (neverZero_counters_str[0] == '3') { */ + // this is the solution we choose because llvm9 should do the right thing here auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0)); auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); /* - } else if (neverZero_counters_str[0] == '6') { + // Solution #4 + } else if (neverZero_counters_str[0] == '4') { auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1)); auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); - - // no other implementations yet - } else { + } else { fprintf(stderr, "Error: unknown value for AFL_NZERO_COUNTS: %s (valid is 1-4)\n", neverZero_counters_str); exit(-1); - } + } */ +#if LLVM_VERSION_MAJOR < 9 } +#endif IRB.CreateStore(Incr, MapPtrIdx)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); -- cgit 1.4.1 From 984ae35948688cac13ce6908aa02fb96d9daf45a Mon Sep 17 00:00:00 2001 From: heiko Date: Fri, 5 Jul 2019 20:02:40 +0200 Subject: increased portability, replace sed with tr (*BSD) sanity check versions from clang and llvm, adjust clang path if needed. --- Makefile | 24 ++++++++++-------------- llvm_mode/Makefile | 48 ++++++++++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 32 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index 14b5ce0e..a9ae5518 100644 --- a/Makefile +++ b/Makefile @@ -38,11 +38,7 @@ CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ PYTHON_INCLUDE ?= /usr/include/python2.7 ifneq "$(filter Linux GNU%,$(shell uname))" "" - LDFLAGS += -ldl -lrt -endif - -ifeq "$(shell uname)" "NetBSD" - LDFLAGS += -lrt + LDFLAGS += -ldl endif ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" @@ -54,7 +50,7 @@ endif COMM_HDR = alloc-inl.h config.h debug.h types.h -ifeq "$(shell echo '\#include XXXvoid main() {}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 && echo 1 || echo 0 )" "1" +ifeq "$(shell echo '\#include @int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 2>/dev/null && echo 1 || echo 0 )" "1" PYTHON_OK=1 PYFLAGS=-DUSE_PYTHON -I$(PYTHON_INCLUDE) -lpython2.7 else @@ -63,18 +59,18 @@ else endif -ifeq "$(shell echo '\#include XXX\#include XXX\#include XXXvoid main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, NULL);}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test2 && echo 1 || echo 0 )" "1" +ifeq "$(shell echo '\#include @\#include @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 SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 - LDFLAGS+=-Wno-deprecated-declarations + LDFLAGS+=-Wno-deprecated-declarations -lrt endif ifeq "$(TEST_MMAP)" "1" SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 - LDFLAGS+=-Wno-deprecated-declarations + LDFLAGS+=-Wno-deprecated-declarations -lrt endif @@ -105,7 +101,7 @@ test_shm: else test_shm: - @echo "[-] shmat seems not to be working, switchig to mmap implementation" + @echo "[-] shmat seems not to be working, switching to mmap implementation" endif @@ -176,10 +172,10 @@ endif all_done: test_build @if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi @echo "[+] All done! Be sure to review the README - it's pretty short and useful." -#ifeq "$(SHMAT_OK)" "0" -# @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" -# @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-gcc CXX=afl-g++ ./configure" -#endif +ifeq "$(SHMAT_OK)" "0" + @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" + @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-gcc CXX=afl-g++ ./configure" +endif @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.txt for advice.\033[0m\n" 2>/dev/null diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index d3e0c739..efabd6b4 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -26,8 +26,9 @@ BIN_PATH = $(PREFIX)/bin VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) LLVM_CONFIG ?= llvm-config +LLVMVER = $(shell $(LLVM_CONFIG) --version) #LLVM_OK = $(shell $(LLVM_CONFIG) --version | egrep -q '^[5-6]' && echo 0 || echo 1 ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version | egrep -q '^9|3.0' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell echo $(LLVMVER) | egrep -q '^9|3.0' && echo 1 || echo 1 ) ifeq "$(LLVM_UNSUPPORTED)" "1" $(warn llvm_mode only supports versions 3.8.0 up to 8.x ) @@ -54,38 +55,46 @@ ifeq "$(shell uname)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress endif -ifeq "$(shell uname)" "NetBSD" - LDFLAGS += -lrt +# 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. + +ifeq "$(origin CC)" "default" + CC = clang + CXX = clang++ endif -ifeq "$(shell echo '\#include XXX\#include XXX\#include XXXvoid main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, NULL);}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test2 && echo 1 || echo 0 )" "1" +# sanity check. +# Are versions of clang --version and llvm-config --version equal? +CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*([0-9]\.[0-9]\.[0-9]).*/s//\1/p') + + +ifeq "$(shell echo '\#include @\#include @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 SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 + LDFLAGS += -lrt endif ifeq "$(TEST_MMAP)" "1" SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 + LDFLAGS += -lrt 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. - -ifeq "$(origin CC)" "default" - CC = clang - CXX = clang++ -endif - ifndef AFL_TRACE_PC PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so else PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so endif +ifneq "$(CLANGVER)" "$(LLVMVER)" + CC = $(shell llvm-config --bindir)/clang + CXX = $(shell llvm-config --bindir)/clang++ +endif + all: test_deps test_shm $(PROGS) test_build all_done @@ -98,7 +107,7 @@ test_shm: else test_shm: - @echo "[-] shmat seems not to be working, switchig to mmap implementation" + @echo "[-] shmat seems not to be working, switching to mmap implementation" endif @@ -112,6 +121,13 @@ else 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 matching versions of '$(CC)' and '$(LLVM_CONFIG)'" +ifneq "$(CLANGVER)" "$(LLVMVER)" + @echo "WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)" + @echo "Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" +else + @echo "we have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good." +endif @echo "[*] Checking for '../afl-showmap'..." @test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 ) @echo "[+] All set and ready to build." @@ -154,10 +170,6 @@ test_build: $(PROGS) all_done: test_build @echo "[+] All done! You can now use '../afl-clang-fast' to compile programs." -#ifeq "$(SHMAT_OK)" "0" -# @echo "[!] shmat isn't working on your platform - compile every target with -lrt:" -# @echo "[!] CFLAGS=-lrt LDFLAGS=-lrt CC=afl-clang-fast CXX=afl-clang-fast++ ./configure" -#endif .NOTPARALLEL: clean -- cgit 1.4.1 From d9c70c7b8cdcde0827e167c61f60f862bc9a3ba8 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 5 Jul 2019 20:33:36 +0200 Subject: add explicit llvm library for OpenBSD --- llvm_mode/Makefile | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'llvm_mode/Makefile') diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index efabd6b4..815ac59d 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -55,6 +55,10 @@ ifeq "$(shell uname)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress endif +ifeq "$(shell uname)" "OpenBSD" + CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so.0.0 +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. -- cgit 1.4.1 From 864056fcaaeea0e156e650b7a0f6182e81db566a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 13 Jul 2019 11:08:13 +0200 Subject: initial commit --- Makefile | 2 +- llvm_mode/LLVMInsTrim.so.cc | 197 ++++++++++++++++++++++++ llvm_mode/Makefile | 6 +- llvm_mode/MarkNodes.cc | 355 ++++++++++++++++++++++++++++++++++++++++++++ llvm_mode/MarkNodes.h | 11 ++ llvm_mode/afl-clang-fast.c | 8 +- 6 files changed, 572 insertions(+), 7 deletions(-) create mode 100644 llvm_mode/LLVMInsTrim.so.cc create mode 100644 llvm_mode/MarkNodes.cc create mode 100644 llvm_mode/MarkNodes.h (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index 601f29a7..0d0d6b79 100644 --- a/Makefile +++ b/Makefile @@ -147,7 +147,7 @@ install: all rm -f $${DESTDIR}$(BIN_PATH)/afl-as if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi ifndef AFL_TRACE_PC - if [ -f afl-clang-fast -a -f afl-llvm-pass.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi + if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi else if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi endif diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc new file mode 100644 index 00000000..2a13981d --- /dev/null +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -0,0 +1,197 @@ +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include +#include + +#include "MarkNodes.h" + +using namespace llvm; + +static cl::opt MarkSetOpt("markset", cl::desc("MarkSet"), + cl::init(false)); +static cl::opt LoopHeadOpt("loophead", cl::desc("LoopHead"), + cl::init(false)); + +namespace { + struct InsTrim : public ModulePass { + private: + std::mt19937 generator; + int total_instr = 0; + + unsigned genLabel() { + return generator() % 65536; + } + + public: + static char ID; + InsTrim() : ModulePass(ID), generator(0) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } + + StringRef getPassName() const override { + return "InstTrim Instrumentation"; + } + + bool runOnModule(Module &M) override { + if (getenv("LOOPHEAD")) { + LoopHeadOpt = true; + MarkSetOpt = true; + } else if (getenv("MARKSET")) { + MarkSetOpt = true; + } + + LLVMContext &C = M.getContext(); + IntegerType *Int8Ty = IntegerType::getInt8Ty(C); + IntegerType *Int32Ty = IntegerType::getInt32Ty(C); + + GlobalVariable *CovMapPtr = new GlobalVariable( + M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage, + nullptr, "__afl_area_ptr"); + + GlobalVariable *OldPrev = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + + unsigned total_rs = 0; + unsigned total_hs = 0; + + for (Function &F : M) { + if (!F.size()) { + continue; + } + + std::unordered_set MS; + if (!MarkSetOpt) { + for (auto &BB : F) { + MS.insert(&BB); + } + total_rs += F.size(); + } else { + auto Result = markNodes(&F); + auto RS = Result.first; + auto HS = Result.second; + + MS.insert(RS.begin(), RS.end()); + if (!LoopHeadOpt) { + MS.insert(HS.begin(), HS.end()); + total_rs += MS.size(); + } else { + DenseSet> EdgeSet; + DominatorTreeWrapperPass *DTWP = + &getAnalysis(F); + auto DT = &DTWP->getDomTree(); + + total_rs += RS.size(); + total_hs += HS.size(); + + for (BasicBlock *BB : HS) { + bool Inserted = false; + for (auto BI = pred_begin(BB), BE = pred_end(BB); + BI != BE; ++BI + ) { + auto Edge = BasicBlockEdge(*BI, BB); + if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) { + EdgeSet.insert({*BI, BB}); + Inserted = true; + break; + } + } + if (!Inserted) { + MS.insert(BB); + total_rs += 1; + total_hs -= 1; + } + } + for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) { + auto PredBB = I->first; + auto SuccBB = I->second; + auto NewBB = SplitBlockPredecessors(SuccBB, {PredBB}, ".split", + DT, nullptr, false); + MS.insert(NewBB); + } + } + + auto *EBB = &F.getEntryBlock(); + if (succ_begin(EBB) == succ_end(EBB)) { + MS.insert(EBB); + total_rs += 1; + } + + for (BasicBlock &BB : F) { + if (MS.find(&BB) == MS.end()) { + continue; + } + IRBuilder<> IRB(&*BB.getFirstInsertionPt()); + IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev); + } + } + + for (BasicBlock &BB : F) { + auto PI = pred_begin(&BB); + auto PE = pred_end(&BB); + if (MarkSetOpt && MS.find(&BB) == MS.end()) { + continue; + } + + IRBuilder<> IRB(&*BB.getFirstInsertionPt()); + Value *L = NULL; + if (PI == PE) { + L = ConstantInt::get(Int32Ty, genLabel()); + } else { + auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); + DenseMap PredMap; + for (auto PI = pred_begin(&BB), PE = pred_end(&BB); + PI != PE; ++PI + ) { + BasicBlock *PBB = *PI; + auto It = PredMap.insert({PBB, genLabel()}); + unsigned Label = It.first->second; + PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB); + } + L = PN; + } + + LoadInst *PrevLoc = IRB.CreateLoad(OldPrev); + Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); + + LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr); + Value *MapPtrIdx = IRB.CreateGEP(MapPtr, + IRB.CreateXor(PrevLocCasted, L)); + + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1)); + IRB.CreateStore(Incr, MapPtrIdx); + total_instr++; + } + } + + errs() << total_instr << " locations instrumented ("<< total_rs << "," << total_hs << ")\n"; + return false; + } + }; // end of struct InsTrim +} // end of anonymous namespace + +char InsTrim::ID = 0; + +static void registerAFLPass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { + PM.add(new InsTrim()); +} + +static RegisterStandardPasses RegisterAFLPass( + PassManagerBuilder::EP_OptimizerLast, registerAFLPass); + +static RegisterStandardPasses RegisterAFLPass0( + PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index b6ab0c61..a66f18ab 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -67,7 +67,7 @@ ifeq "$(origin CC)" "default" endif ifndef AFL_TRACE_PC - PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so + PROGS = ../afl-clang-fast ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so else PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so endif @@ -91,8 +91,8 @@ endif $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) ln -sf afl-clang-fast ../afl-clang-fast++ -../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) +../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps + $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=gnu++11 -shared $< -o $@ $(CLANG_LFL) # laf ../split-switches-pass.so: split-switches-pass.so.cc | test_deps diff --git a/llvm_mode/MarkNodes.cc b/llvm_mode/MarkNodes.cc new file mode 100644 index 00000000..3c2129ef --- /dev/null +++ b/llvm_mode/MarkNodes.cc @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +DenseMap LMap; +std::vector Blocks; +std::set Marked , Markabove; +std::vector< std::vector > Succs , Preds; + +void reset(){ + LMap.clear(); + Blocks.clear(); + Marked.clear(); + Markabove.clear(); +} + +uint32_t start_point; + +void labelEachBlock(Function *F) { + // Fake single endpoint; + LMap[NULL] = Blocks.size(); + Blocks.push_back(NULL); + + // Assign the unique LabelID to each block; + for (auto I = F->begin(), E = F->end(); I != E; ++I) { + BasicBlock *BB = &*I; + LMap[BB] = Blocks.size(); + Blocks.push_back(BB); + } + + start_point = LMap[&F->getEntryBlock()]; +} + +void buildCFG(Function *F) { + Succs.resize( Blocks.size() ); + Preds.resize( Blocks.size() ); + for( size_t i = 0 ; i < Succs.size() ; i ++ ){ + Succs[ i ].clear(); + Preds[ i ].clear(); + } + + uint32_t FakeID = 0; + for (auto S = F->begin(), E = F->end(); S != E; ++S) { + BasicBlock *BB = &*S; + uint32_t MyID = LMap[BB]; + //if (succ_begin(BB) == succ_end(BB)) { + //Succs[MyID].push_back(FakeID); + //Marked.insert(MyID); + //} + for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { + Succs[MyID].push_back(LMap[*I]); + } + } +} + +std::vector< std::vector > tSuccs; +std::vector tag , indfs; + +void DFStree(size_t now_id) { + if(tag[now_id]) return; + tag[now_id]=true; + indfs[now_id]=true; + for (auto succ: tSuccs[now_id]) { + if(tag[succ] and indfs[succ]) { + Marked.insert(succ); + Markabove.insert(succ); + continue; + } + Succs[now_id].push_back(succ); + Preds[succ].push_back(now_id); + DFStree(succ); + } + indfs[now_id]=false; +} +void turnCFGintoDAG(Function *F) { + tSuccs = Succs; + tag.resize(Blocks.size()); + indfs.resize(Blocks.size()); + for (size_t i = 0; i < Blocks.size(); ++ i) { + Succs[i].clear(); + tag[i]=false; + indfs[i]=false; + } + DFStree(start_point); + for (size_t i = 0; i < Blocks.size(); ++ i) + if( Succs[i].empty() ){ + Succs[i].push_back(0); + Preds[0].push_back(i); + } +} + +uint32_t timeStamp; +namespace DominatorTree{ + std::vector< std::vector > cov; + std::vector dfn, nfd, par, sdom, idom, mom, mn; + + bool Compare(uint32_t u, uint32_t v) { + return dfn[u] < dfn[v]; + } + uint32_t eval(uint32_t u) { + if( mom[u] == u ) return u; + uint32_t res = eval( mom[u] ); + if(Compare(sdom[mn[mom[u]]] , sdom[mn[u]])) { + mn[u] = mn[mom[u]]; + } + return mom[u] = res; + } + + void DFS(uint32_t now) { + timeStamp += 1; + dfn[now] = timeStamp; + nfd[timeStamp - 1] = now; + for( auto succ : Succs[now] ) { + if( dfn[succ] == 0 ) { + par[succ] = now; + DFS(succ); + } + } + } + + void DominatorTree(Function *F) { + if( Blocks.empty() ) return; + uint32_t s = start_point; + + // Initialization + mn.resize(Blocks.size()); + cov.resize(Blocks.size()); + dfn.resize(Blocks.size()); + nfd.resize(Blocks.size()); + par.resize(Blocks.size()); + mom.resize(Blocks.size()); + sdom.resize(Blocks.size()); + idom.resize(Blocks.size()); + + for( uint32_t i = 0 ; i < Blocks.size() ; i ++ ) { + dfn[i] = 0; + nfd[i] = Blocks.size(); + cov[i].clear(); + idom[i] = mom[i] = mn[i] = sdom[i] = i; + } + + timeStamp = 0; + DFS(s); + + for( uint32_t i = Blocks.size() - 1 ; i >= 1u ; i -- ) { + uint32_t now = nfd[i]; + if( now == Blocks.size() ) { + continue; + } + for( uint32_t pre : Preds[ now ] ) { + if( dfn[ pre ] ) { + eval(pre); + if( Compare(sdom[mn[pre]], sdom[now]) ) { + sdom[now] = sdom[mn[pre]]; + } + } + } + cov[sdom[now]].push_back(now); + mom[now] = par[now]; + for( uint32_t x : cov[par[now]] ) { + eval(x); + if( Compare(sdom[mn[x]], par[now]) ) { + idom[x] = mn[x]; + } else { + idom[x] = par[now]; + } + } + } + + for( uint32_t i = 1 ; i < Blocks.size() ; i += 1 ) { + uint32_t now = nfd[i]; + if( now == Blocks.size() ) { + continue; + } + if(idom[now] != sdom[now]) + idom[now] = idom[idom[now]]; + } + } +}; // End of DominatorTree + +std::vector Visited, InStack; +std::vector TopoOrder, InDeg; +std::vector< std::vector > t_Succ , t_Pred; + +void Go(uint32_t now, uint32_t tt) { + if( now == tt ) return; + Visited[now] = InStack[now] = timeStamp; + + for(uint32_t nxt : Succs[now]) { + if(Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) { + Marked.insert(nxt); + } + t_Succ[now].push_back(nxt); + t_Pred[nxt].push_back(now); + InDeg[nxt] += 1; + if(Visited[nxt] == timeStamp) { + continue; + } + Go(nxt, tt); + } + + InStack[now] = 0; +} + +void TopologicalSort(uint32_t ss, uint32_t tt) { + timeStamp += 1; + + Go(ss, tt); + + TopoOrder.clear(); + std::queue wait; + wait.push(ss); + while( not wait.empty() ) { + uint32_t now = wait.front(); wait.pop(); + TopoOrder.push_back(now); + for(uint32_t nxt : t_Succ[now]) { + InDeg[nxt] -= 1; + if(InDeg[nxt] == 0u) { + wait.push(nxt); + } + } + } +} + +std::vector< std::set > NextMarked; +bool Indistinguish(uint32_t node1, uint32_t node2) { + if(NextMarked[node1].size() > NextMarked[node2].size()){ + uint32_t _swap = node1; + node1 = node2; + node2 = _swap; + } + for(uint32_t x : NextMarked[node1]) { + if( NextMarked[node2].find(x) != NextMarked[node2].end() ) { + return true; + } + } + return false; +} + +void MakeUniq(uint32_t now) { + bool StopFlag = false; + if (Marked.find(now) == Marked.end()) { + for(uint32_t pred1 : t_Pred[now]) { + for(uint32_t pred2 : t_Pred[now]) { + if(pred1 == pred2) continue; + if(Indistinguish(pred1, pred2)) { + Marked.insert(now); + StopFlag = true; + break; + } + } + if (StopFlag) { + break; + } + } + } + if(Marked.find(now) != Marked.end()) { + NextMarked[now].insert(now); + } else { + for(uint32_t pred : t_Pred[now]) { + for(uint32_t x : NextMarked[pred]) { + NextMarked[now].insert(x); + } + } + } +} + +void MarkSubGraph(uint32_t ss, uint32_t tt) { + TopologicalSort(ss, tt); + if(TopoOrder.empty()) return; + + for(uint32_t i : TopoOrder) { + NextMarked[i].clear(); + } + + NextMarked[TopoOrder[0]].insert(TopoOrder[0]); + for(uint32_t i = 1 ; i < TopoOrder.size() ; i += 1) { + MakeUniq(TopoOrder[i]); + } +} + +void MarkVertice(Function *F) { + uint32_t s = start_point; + + InDeg.resize(Blocks.size()); + Visited.resize(Blocks.size()); + InStack.resize(Blocks.size()); + t_Succ.resize(Blocks.size()); + t_Pred.resize(Blocks.size()); + NextMarked.resize(Blocks.size()); + + for( uint32_t i = 0 ; i < Blocks.size() ; i += 1 ) { + Visited[i] = InStack[i] = InDeg[i] = 0; + t_Succ[i].clear(); + t_Pred[i].clear(); + } + timeStamp = 0; + uint32_t t = 0; + //MarkSubGraph(s, t); + //return; + + while( s != t ) { + MarkSubGraph(DominatorTree::idom[t], t); + t = DominatorTree::idom[t]; + } + +} + +// return {marked nodes} +std::pair, + std::vector >markNodes(Function *F) { + assert(F->size() > 0 && "Function can not be empty"); + + reset(); + labelEachBlock(F); + buildCFG(F); + turnCFGintoDAG(F); + DominatorTree::DominatorTree(F); + MarkVertice(F); + + std::vector Result , ResultAbove; + for( uint32_t x : Markabove ) { + auto it = Marked.find( x ); + if( it != Marked.end() ) + Marked.erase( it ); + if( x ) + ResultAbove.push_back(Blocks[x]); + } + for( uint32_t x : Marked ) { + if (x == 0) { + continue; + } else { + Result.push_back(Blocks[x]); + } + } + + return { Result , ResultAbove }; +} diff --git a/llvm_mode/MarkNodes.h b/llvm_mode/MarkNodes.h new file mode 100644 index 00000000..e3bf3ce5 --- /dev/null +++ b/llvm_mode/MarkNodes.h @@ -0,0 +1,11 @@ +#ifndef __MARK_NODES__ +#define __MARK_NODES__ + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include + +std::pair, + std::vector> markNodes(llvm::Function *F); + +#endif diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 5bc4ae8c..2034f10a 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -32,6 +32,7 @@ #include #include #include +#include static u8* obj_path; /* Path to runtime libraries */ static u8** cc_params; /* Parameters passed to the real CC */ @@ -87,7 +88,7 @@ static void find_obj(u8* argv0) { return; } - FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH"); + FATAL("Unable to find 'afl-llvm-rt.o' or 'libLLVMInsTrim.so'. Please set AFL_PATH"); } @@ -113,7 +114,7 @@ static void edit_params(u32 argc, char** argv) { } /* 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 + use libLLVMInsTrim.so to inject instrumentation. In the experimental 'trace-pc-guard' mode, we use native LLVM instrumentation callbacks instead. The latter is a very recent addition - see: @@ -150,7 +151,8 @@ static void edit_params(u32 argc, char** argv) { 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); + cc_params[cc_par_cnt++] = alloc_printf("%s/libLLVMInsTrim.so", obj_path); +// 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"; -- cgit 1.4.1 From 98a696391183274fd683383d015646ac28e64182 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 14 Jul 2019 10:05:46 +0200 Subject: make fix --- llvm_mode/Makefile | 2 +- llvm_mode/MarkNodes.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index a66f18ab..2947dc9b 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -92,7 +92,7 @@ endif ln -sf afl-clang-fast ../afl-clang-fast++ ../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps - $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=gnu++11 -shared $< -o $@ $(CLANG_LFL) + $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=gnu++11 -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) # laf ../split-switches-pass.so: split-switches-pass.so.cc | test_deps diff --git a/llvm_mode/MarkNodes.cc b/llvm_mode/MarkNodes.cc index 3c2129ef..a156fccb 100644 --- a/llvm_mode/MarkNodes.cc +++ b/llvm_mode/MarkNodes.cc @@ -56,7 +56,7 @@ void buildCFG(Function *F) { Preds[ i ].clear(); } - uint32_t FakeID = 0; + //uint32_t FakeID = 0; for (auto S = F->begin(), E = F->end(); S != E; ++S) { BasicBlock *BB = &*S; uint32_t MyID = LMap[BB]; -- cgit 1.4.1 From 32525238238e96ec0ce64a36f70558f76bc90ff5 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 15 Jul 2019 11:22:54 +0200 Subject: fixing commit fuckup --- Makefile | 2 +- docs/ChangeLog | 8 +++----- docs/README | 3 +-- docs/env_variables.txt | 22 +++++++++++++++++----- llvm_mode/LLVMInsTrim.so.cc | 2 +- llvm_mode/Makefile | 13 ++++++++----- llvm_mode/README.llvm | 19 ++++++++++++------- llvm_mode/afl-clang-fast.c | 16 +++++++++------- 8 files changed, 52 insertions(+), 33 deletions(-) (limited to 'llvm_mode/Makefile') diff --git a/Makefile b/Makefile index 60dfde18..6b580381 100644 --- a/Makefile +++ b/Makefile @@ -194,7 +194,7 @@ install: all rm -f $${DESTDIR}$(BIN_PATH)/afl-as if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi ifndef AFL_TRACE_PC - if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi + if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi else if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi endif diff --git a/docs/ChangeLog b/docs/ChangeLog index 9cdca49b..116029ea 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -17,9 +17,9 @@ sending a mail to . Version ++2.52d (tbd): ----------------------------- - - added instrim a much better llvm_mode instrumentation - (https://github.com/csienslab/instrim) - - added MOpt (github.com/puppet-meteor/MOpt-AFL) mode + - added instrim, a much faster llvm_mode instrumentation at the cost of + path discovery. See llvm_mode/README.instrim (https://github.com/csienslab/instrim) + - added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt - added code to make it more portable to other platforms than Intel Linux - added never zero counters for afl-gcc and optional (because of an optimization issue in llvm < 9) for llvm_mode (AFL_LLVM_NEVER_ZERO=1) @@ -41,8 +41,6 @@ Version ++2.52d (tbd): tests as the random numbers are deterministic then - llvm_mode LAF_... env variables can now be specified as AFL_LLVM_LAF_... that is longer but in line with other llvm specific env vars - - ... your idea or patch? - ----------------------------- diff --git a/docs/README b/docs/README index 54e3e4a4..3a6c2921 100644 --- a/docs/README +++ b/docs/README @@ -23,8 +23,7 @@ american fuzzy lop plus plus https://github.com/puppet-meteor/MOpt-AFL Also newly integrated is instrim, a very effective CFG llvm_mode - instrumentation implementation which replaced the original afl one and is - from https://github.com/csienslab/instrim + instrumentation implementation from https://github.com/csienslab/instrim A more thorough list is available in the PATCHES file. diff --git a/docs/env_variables.txt b/docs/env_variables.txt index 8e2723d7..e58327b4 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -109,11 +109,21 @@ Then there are a few specific features that are only available in llvm_mode: See llvm_mode/README.whitelist for more information. - OTHER - ===== - - Setting LOOPHEAD=1 optimized loops. afl-fuzz will only be able to - see the path the loop took, but not how many times it was called - (unless its a complex loop). + INSTRIM + ======= + This feature increases the speed by whopping 20% but at the cost of a + lower path discovery and thefore coverage. + + - Setting AFL_LLVM_INSTRIM activates this mode + + - Setting AFL_LLVM_INSTRIM LOOPHEAD=1 expands on INSTRIM to optimize loops. + afl-fuzz will only be able to see the path the loop took, but not how + many times it was called (unless its a complex loop). + + See llvm_mode/README.instrim + + NOT_ZERO + ======== - Setting AFL_LLVM_NOT_ZERO=1 during compilation will use counters that skip zero on overflow. This is the default for llvm >= 9, @@ -121,6 +131,8 @@ Then there are a few specific features that are only available in llvm_mode: slowdown due a performance issue that is only fixed in llvm 9+. This feature increases path discovery by a little bit. + See llvm_mode/README.neverzero + 3) Settings for afl-fuzz ------------------------ diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 8e9f7667..81cf98c4 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -96,7 +96,7 @@ namespace { OKF("LLVM neverZero activated (by hexcoder)\n"); #endif - if (getenv("LOOPHEAD")) { + if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL || getenv("LOOPHEAD") != NULL) { LoopHeadOpt = true; } diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index d0d4b690..2b685ddc 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -94,7 +94,7 @@ endif ifndef AFL_TRACE_PC - PROGS = ../afl-clang-fast ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so + PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so else PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so endif @@ -104,7 +104,7 @@ ifneq "$(CLANGVER)" "$(LLVMVER)" CXX = $(shell llvm-config --bindir)/clang++ endif -all: test_deps test_shm $(PROGS) test_build all_done +all: test_shm test_deps $(PROGS) test_build all_done ifeq "$(SHMAT_OK)" "1" @@ -132,10 +132,10 @@ endif @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 matching versions of '$(CC)' and '$(LLVM_CONFIG)'" ifneq "$(CLANGVER)" "$(LLVMVER)" - @echo "WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)" - @echo "Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" + @echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)" + @echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" else - @echo "we have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good." + @echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good." endif @echo "[*] Checking for '../afl-showmap'..." @test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 ) @@ -148,6 +148,9 @@ endif ../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=gnu++11 -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) +../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps + $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=gnu++11 -shared $< -o $@ $(CLANG_LFL) + # laf ../split-switches-pass.so: split-switches-pass.so.cc | test_deps $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) diff --git a/llvm_mode/README.llvm b/llvm_mode/README.llvm index 77c406f8..779ff47c 100644 --- a/llvm_mode/README.llvm +++ b/llvm_mode/README.llvm @@ -88,13 +88,18 @@ which C/C++ files to actually intrument. See README.whitelist For splitting memcmp, strncmp, etc. please see README.laf-intel -As the original afl llvm_mode implementation has been replaced with -then much more effective instrim (https://github.com/csienslab/instrim/) -there is an option for optimizing loops. This optimization shows which -part of the loop has been selected, but not how many time a loop has been -called in a row (unless its a complex loop and a block inside was -instrumented). If you want to enable this set the environment variable -LOOPHEAD=1 +Then there is an optimized instrumentation strategy that uses CFGs and +markers to just instrument what is needed. This increases speed by 20-25% +however has a lower path discovery. +If you want to use this, set AFL_LLVM_INSTRIM=1 +See README.instrim + +Finally if your llvm version is 8 or lower, you can activate a mode that +prevents that a counter overflow result in a 0 value. This is good for +path discovery, but the llvm implementation for intel for this functionality +is not optimal and was only fixed in llvm 9. +You can set this with AFL_LLVM_NOT_ZERO=1 +See README.neverzero 4) Gotchas, feedback, bugs diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 249eea7d..19bad86c 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -88,7 +88,7 @@ static void find_obj(u8* argv0) { return; } - FATAL("Unable to find 'afl-llvm-rt.o' or 'libLLVMInsTrim.so'. Please set AFL_PATH"); + FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so.cc'. Please set AFL_PATH"); } @@ -113,11 +113,11 @@ 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 libLLVMInsTrim.so to inject instrumentation. In the experimental + /* There are three ways to compile with afl-clang-fast. In the traditional + mode, we use afl-llvm-pass.so, then there is libLLVMInsTrim.so which is + much faster but has less coverage. Finally tere is the experimental 'trace-pc-guard' mode, we use native LLVM instrumentation callbacks - instead. The latter is a very recent addition - see: - + instead. For trace-pc-guard see: http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */ // laf @@ -151,8 +151,10 @@ static void edit_params(u32 argc, char** argv) { 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/libLLVMInsTrim.so", obj_path); -// cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); + if (getenv("AFL_LLVM_INSTRIM") != NULL || getenv("INSTRIM_LIB") != NULL) + cc_params[cc_par_cnt++] = alloc_printf("%s/libLLVMInsTrim.so", obj_path); + else + 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"; -- cgit 1.4.1