diff options
-rw-r--r-- | GNUmakefile.gcc_plugin (renamed from gcc_plugin/GNUmakefile) | 97 | ||||
-rw-r--r-- | GNUmakefile.llvm (renamed from llvm_mode/GNUmakefile) | 205 | ||||
-rw-r--r-- | gcc_plugin/Makefile | 159 | ||||
-rw-r--r-- | gcc_plugin/README.instrument_list.md | 73 | ||||
-rw-r--r-- | gcc_plugin/afl-gcc-fast.c | 406 | ||||
-rw-r--r-- | gcc_plugin/afl-gcc-rt.o.c | 315 | ||||
-rw-r--r-- | instrumentation/LLVMInsTrim.so.cc (renamed from llvm_mode/LLVMInsTrim.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/MarkNodes.cc (renamed from llvm_mode/MarkNodes.cc) | 0 | ||||
-rw-r--r-- | instrumentation/MarkNodes.h (renamed from llvm_mode/MarkNodes.h) | 0 | ||||
-rw-r--r-- | instrumentation/README.cmplog.md (renamed from llvm_mode/README.cmplog.md) | 4 | ||||
-rw-r--r-- | instrumentation/README.ctx.md (renamed from llvm_mode/README.ctx.md) | 2 | ||||
-rw-r--r-- | instrumentation/README.gcc_plugin.md (renamed from gcc_plugin/README.md) | 2 | ||||
-rw-r--r-- | instrumentation/README.instrim.md | 30 | ||||
-rw-r--r-- | instrumentation/README.instrument_list.md (renamed from llvm_mode/README.instrument_list.md) | 37 | ||||
-rw-r--r-- | instrumentation/README.laf-intel.md (renamed from llvm_mode/README.laf-intel.md) | 18 | ||||
-rw-r--r-- | instrumentation/README.llvm.md (renamed from llvm_mode/README.md) | 44 | ||||
-rw-r--r-- | instrumentation/README.lto.md (renamed from llvm_mode/README.lto.md) | 33 | ||||
-rw-r--r-- | instrumentation/README.neverzero.md (renamed from llvm_mode/README.neverzero.md) | 4 | ||||
-rw-r--r-- | instrumentation/README.ngram.md (renamed from llvm_mode/README.ngram.md) | 0 | ||||
-rw-r--r-- | instrumentation/README.persistent_mode.md (renamed from llvm_mode/README.persistent_mode.md) | 14 | ||||
-rw-r--r-- | instrumentation/README.snapshot.md (renamed from llvm_mode/README.snapshot.md) | 2 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc (renamed from llvm_mode/SanitizerCoverageLTO.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-compiler-rt.o.c (renamed from llvm_mode/afl-llvm-rt.o.c) | 30 | ||||
-rw-r--r-- | instrumentation/afl-gcc-pass.so.cc (renamed from gcc_plugin/afl-gcc-pass.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-common.cc (renamed from llvm_mode/afl-llvm-common.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-common.h (renamed from llvm_mode/afl-llvm-common.h) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-dict2file.so.cc | 599 | ||||
-rw-r--r-- | instrumentation/afl-llvm-lto-instrumentation.so.cc (renamed from llvm_mode/afl-llvm-lto-instrumentation.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-lto-instrumentlist.so.cc (renamed from llvm_mode/afl-llvm-lto-instrumentlist.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-pass.so.cc (renamed from llvm_mode/afl-llvm-pass.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/afl-llvm-rt-lto.o.c (renamed from llvm_mode/afl-llvm-rt-lto.o.c) | 0 | ||||
-rw-r--r-- | instrumentation/cmplog-instructions-pass.cc (renamed from llvm_mode/cmplog-instructions-pass.cc) | 0 | ||||
-rw-r--r-- | instrumentation/cmplog-routines-pass.cc (renamed from llvm_mode/cmplog-routines-pass.cc) | 0 | ||||
-rw-r--r-- | instrumentation/compare-transform-pass.so.cc (renamed from llvm_mode/compare-transform-pass.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/llvm-ngram-coverage.h (renamed from llvm_mode/llvm-ngram-coverage.h) | 0 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc (renamed from llvm_mode/split-compares-pass.so.cc) | 0 | ||||
-rw-r--r-- | instrumentation/split-switches-pass.so.cc (renamed from llvm_mode/split-switches-pass.so.cc) | 0 | ||||
-rw-r--r-- | llvm_mode/Makefile | 2 | ||||
-rw-r--r-- | llvm_mode/README.instrim.md | 25 | ||||
-rw-r--r-- | llvm_mode/afl-clang-fast.c | 1143 | ||||
-rw-r--r-- | src/afl-cc.c | 1544 | ||||
-rw-r--r-- | src/afl-gcc.c | 488 | ||||
-rw-r--r-- | src/afl-ld-lto.c (renamed from llvm_mode/afl-ld-lto.c) | 0 |
43 files changed, 2442 insertions, 2834 deletions
diff --git a/gcc_plugin/GNUmakefile b/GNUmakefile.gcc_plugin index 625b55fb..aeb1ef16 100644 --- a/gcc_plugin/GNUmakefile +++ b/GNUmakefile.gcc_plugin @@ -26,10 +26,10 @@ BIN_PATH ?= $(PREFIX)/bin DOC_PATH ?= $(PREFIX)/share/doc/afl MAN_PATH ?= $(PREFIX)/share/man/man8 -VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) +VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2 -CFLAGS_SAFE := -Wall -I../include -Wno-pointer-sign \ +CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \ -Wno-unused-function @@ -80,25 +80,22 @@ ifeq "$(shell uname -s)" "SunOS" endif -PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o +PROGS = ./afl-gcc-pass.so +.PHONY: all +all: test_shm test_deps $(PROGS) test_build all_done -all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done - +.PHONY: test_shm 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, switching to mmap implementation" - endif - +.PHONY: test_deps test_deps: @echo "[*] Checking for working '$(CC)'..." @type $(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 ) @@ -106,65 +103,65 @@ test_deps: # @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 ) @echo "[*] Checking for gcc plugin development header files..." @test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 ) - @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 "[*] 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." -afl-common.o: ../src/afl-common.c +afl-common.o: ./src/afl-common.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS) -../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps - $(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $(CPPFLAGS) $< afl-common.o -o $@ $(LDFLAGS) - ln -sf afl-gcc-fast ../afl-g++-fast - -../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps +./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ + ln -sf afl-cc afl-gcc-fast + ln -sf afl-cc afl-g++-fast + ln -sf afl-cc.8 afl-gcc-fast.8 + ln -sf afl-cc.8 afl-g++-fast.8 -../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps - $(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -fPIC -c $< -o $@ - +.PHONY: test_build test_build: $(PROGS) @echo "[*] Testing the CC wrapper and instrumentation output..." - unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) -# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) - ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null - echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr + unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS) + ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null + echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi @echo "[+] All right, the instrumentation seems to be working!" +.PHONY: all_done all_done: test_build - @echo "[+] All done! You can now use '../afl-gcc-fast' to compile programs." + @echo "[+] All done! You can now use './afl-gcc-fast' to compile programs." .NOTPARALLEL: clean vpath % .. %.8: % - @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@ - @echo .SH NAME >> ../$@ - @echo .B $* >> ../$@ - @echo >> ../$@ - @echo .SH SYNOPSIS >> ../$@ - @../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@ - @echo >> ../$@ - @echo .SH OPTIONS >> ../$@ - @echo .nf >> ../$@ - @../$* -h 2>&1 | tail -n +4 >> ../$@ - @echo >> ../$@ - @echo .SH AUTHOR >> ../$@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@ - @echo >> ../$@ - @echo .SH LICENSE >> ../$@ - @echo Apache License Version 2.0, January 2004 >> ../$@ - ln -sf afl-gcc-fast.8 ../afl-g++-fast.8 - + @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@ + @echo .SH NAME >> ./$@ + @echo .B $* >> ./$@ + @echo >> ./$@ + @echo .SH SYNOPSIS >> ./$@ + @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@ + @echo >> ./$@ + @echo .SH OPTIONS >> ./$@ + @echo .nf >> ./$@ + @./$* -h 2>&1 | tail -n +4 >> ./$@ + @echo >> ./$@ + @echo .SH AUTHOR >> ./$@ + @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@ + @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ + @echo >> ./$@ + @echo .SH LICENSE >> ./$@ + @echo Apache License Version 2.0, January 2004 >> ./$@ + ln -sf afl-cc.8 ./afl-g++-fast.8 + +.PHONY: install install: all - install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH) - install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH) - install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md - install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md + ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast + ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast + install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH) + install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md +.PHONY: clean clean: rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2 - rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8 + rm -f $(PROGS) afl-common.o ./afl-g++-fast ./afl-g*-fast.8 instrumentation/*.o diff --git a/llvm_mode/GNUmakefile b/GNUmakefile.llvm index c14e8b4e..d4502319 100644 --- a/llvm_mode/GNUmakefile +++ b/GNUmakefile.llvm @@ -26,10 +26,10 @@ DOC_PATH ?= $(PREFIX)/share/doc/afl MISC_PATH ?= $(PREFIX)/share/afl MAN_PATH ?= $(PREFIX)/share/man/man8 -VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) - BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d") +VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) + ifeq "$(shell uname)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) @@ -41,6 +41,7 @@ else endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' ) +LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^19' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 ) @@ -78,13 +79,13 @@ ifeq "$(LLVM_TOO_OLD)" "1" endif ifeq "$(LLVM_HAVE_LTO)" "1" - $(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation) + $(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation) LLVM_LTO = 1 #TEST_MMAP = 1 endif ifeq "$(LLVM_LTO)" "0" - $(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.) + $(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.) endif ifeq "$(LLVM_APPLE_XCODE)" "1" @@ -224,7 +225,7 @@ else endif CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2 -CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \ +CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \ -DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \ @@ -241,7 +242,7 @@ ifdef AFL_TRACE_PC endif CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2 -override CXXFLAGS += -Wall -g -I ../include/ \ +override CXXFLAGS += -Wall -g -I ./include/ \ -DVERSION=\"$(VERSION)\" -Wno-variadic-macros ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" "" @@ -283,7 +284,8 @@ ifeq "$(TEST_MMAP)" "1" LDFLAGS += -Wno-deprecated-declarations endif -PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.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 ../cmplog-routines-pass.so ../cmplog-instructions-pass.so ../SanitizerCoverageLTO.so +PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o +PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so # If prerequisites are not given, warn, do not build anything, and exit with code 0 ifeq "$(LLVMVER)" "" @@ -295,31 +297,31 @@ ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00" endif ifeq "$(NO_BUILD)" "1" - TARGETS = no_build + TARGETS = test_shm $(PROGS_ALWAYS) afl-cc.8 else - TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done + TARGETS = test_shm test_deps $(PROGS) afl-cc.8 test_build all_done endif LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?) +.PHONY: all all: $(TARGETS) +.PHONY: test_shm 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, switching to mmap implementation" - endif +.PHONY: no_build no_build: @printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m" +.PHONY: test_deps test_deps: @echo "[*] Checking for working 'llvm-config'..." ifneq "$(LLVM_APPLE_XCODE)" "1" @@ -333,148 +335,165 @@ ifneq "$(CLANGVER)" "$(LLVMVER)" 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 "[*] 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." -afl-common.o: ../src/afl-common.c +instrumentation/afl-common.o: ./src/afl-common.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS) -../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps - $(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" - ln -sf afl-clang-fast ../afl-clang-fast++ +./afl-cc: src/afl-cc.c instrumentation/afl-common.o | test_deps + $(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" + @ln -sf afl-cc ./afl-c++ + @ln -sf afl-cc ./afl-gcc + @ln -sf afl-cc ./afl-g++ + @ln -sf afl-cc ./afl-clang-fast + @ln -sf afl-cc ./afl-clang-fast++ ifneq "$(AFL_CLANG_FLTO)" "" ifeq "$(LLVM_LTO)" "1" - ln -sf afl-clang-fast ../afl-clang-lto - ln -sf afl-clang-fast ../afl-clang-lto++ + @ln -sf afl-cc ./afl-clang-lto + @ln -sf afl-cc ./afl-clang-lto++ + @ln -sf afl-cc ./afl-lto + @ln -sf afl-cc ./afl-lto++ endif endif -afl-llvm-common.o: afl-llvm-common.cc afl-llvm-common.h +instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h $(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ -../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc afl-llvm-common.o | test_deps - -$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o +./libLLVMInsTrim.so: instrumentation/LLVMInsTrim.so.cc instrumentation/MarkNodes.cc instrumentation/afl-llvm-common.o | test_deps + -$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< instrumentation/MarkNodes.cc -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o -../afl-llvm-pass.so: afl-llvm-pass.so.cc afl-llvm-common.o | test_deps +./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ifeq "$(LLVM_MIN_4_0_1)" "0" $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER)) endif - $(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o + $(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o -../afl-llvm-lto-instrumentlist.so: afl-llvm-lto-instrumentlist.so.cc afl-llvm-common.o +./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" - $(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o + $(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o endif -../afl-ld-lto: afl-ld-lto.c +./afl-ld-lto: src/afl-ld-lto.c ifeq "$(LLVM_LTO)" "1" $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ endif -../SanitizerCoverageLTO.so: SanitizerCoverageLTO.so.cc +./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc ifeq "$(LLVM_LTO)" "1" - $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o + $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o endif -../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o +./afl-llvm-lto-instrumentation.so: instrumentation/afl-llvm-lto-instrumentation.so.cc instrumentation/afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" - $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o - $(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o - @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi - @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi + $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o + $(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o + @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi + @$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi endif # laf -../split-switches-pass.so: split-switches-pass.so.cc afl-llvm-common.o | test_deps - $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o -../compare-transform-pass.so: compare-transform-pass.so.cc afl-llvm-common.o | test_deps - $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o -../split-compares-pass.so: split-compares-pass.so.cc afl-llvm-common.o | test_deps - $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o +./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o +./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o +./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o # /laf -../cmplog-routines-pass.so: cmplog-routines-pass.cc afl-llvm-common.o | test_deps - $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o +./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o + +./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o -../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps - $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o +afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o +.PHONY: document document: - $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o - @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi - @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt.o + @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi -../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps +./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c | test_deps $(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@ + ln -sf ./afl-compiler-rt.o ./afl-llvm-rt.o -../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps +./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 32-bit variant of the runtime (-m32)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e ./afl-compiler-rt-32.o && ln -sf ./afl-compiler-rt-32.o ./afl-llvm-rt-32.o -../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps +./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 64-bit variant of the runtime (-m64)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e ./afl-compiler-rt-64.o && ln -sf ./afl-compiler-rt-64.o ./afl-llvm-rt-64.o +.PHONY: test_build 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_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) - ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null - echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr + unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS) + ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null + echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi @echo "[+] All right, the instrumentation seems to be working!" +.PHONY: all_done all_done: test_build - @echo "[+] All done! You can now use '../afl-clang-fast' to compile programs." + @echo "[+] All done! You can now use './afl-cc' to compile programs." .NOTPARALLEL: clean +.PHONY: install install: all - install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) - 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 - if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../afl-ld-lto ]; then set -e; install -m 755 ../afl-ld-lto $${DESTDIR}$(BIN_PATH); fi - if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../split-compares-pass.so ]; then set -e; install -m 755 ../split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../split-switches-pass.so ]; then set -e; install -m 755 ../split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../cmplog-instructions-pass.so ]; then set -e; install -m 755 ../cmplog-*-pass.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../SanitizerCoverageLTO.so ]; then set -e; install -m 755 ../SanitizerCoverageLTO.so $${DESTDIR}$(HELPER_PATH); fi - set -e; install -m 644 ../dynamic_list.txt $${DESTDIR}$(HELPER_PATH) - set -e; if [ -f ../afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi - install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/ - install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md + @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) + @if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi + @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi + @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o; fi + @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o; fi + @if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi + @if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi + set -e; install -m 644 ./dynamic_list.txt $${DESTDIR}$(HELPER_PATH) + install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/ vpath % .. %.8: % - @echo .TH $* 8 $(BUILD_DATE) "afl++" > ../$@ - @echo .SH NAME >> ../$@ - @echo -n ".B $* \- " >> ../$@ - @../$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ../$@ - @echo >> ../$@ - @echo .SH SYNOPSIS >> ../$@ - @../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@ - @echo >> ../$@ - @echo .SH OPTIONS >> ../$@ - @echo .nf >> ../$@ - @../$* -h 2>&1 | tail -n +4 >> ../$@ - @echo >> ../$@ - @echo .SH AUTHOR >> ../$@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@ - @echo >> ../$@ - @echo .SH LICENSE >> ../$@ - @echo Apache License Version 2.0, January 2004 >> ../$@ - ln -sf afl-clang-fast.8 ../afl-clang-fast++.8 + @echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@ + @echo .SH NAME >> ./$@ + @printf ".B $* \- " >> ../$@ + @./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ../$@ + @echo .B $* >> ./$@ + @echo >> ./$@ + @echo .SH SYNOPSIS >> ./$@ + @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@ + @echo >> ./$@ + @echo .SH OPTIONS >> ./$@ + @echo .nf >> ./$@ + @./$* -h 2>&1 | tail -n +4 >> ./$@ + @echo >> ./$@ + @echo .SH AUTHOR >> ./$@ + @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@ + @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ + @echo >> ./$@ + @echo .SH LICENSE >> ./$@ + @echo Apache License Version 2.0, January 2004 >> ./$@ + @ln -sf afl-cc.8 ./afl-c++.8 ifneq "$(AFL_CLANG_FLTO)" "" ifeq "$(LLVM_LTO)" "1" - ln -sf afl-clang-fast.8 ../afl-clang-lto.8 - ln -sf afl-clang-fast.8 ../afl-clang-lto++.8 + @ln -sf afl-cc.8 ./afl-clang-lto.8 + @ln -sf afl-cc.8 ./afl-clang-lto++.8 + @ln -sf afl-cc.8 ./afl-lto.8 + @ln -sf afl-cc.8 ./afl-lto++.8 endif endif +.PHONY: clean clean: rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo - rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld ../afl-ld ../afl-llvm-rt*.o + rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-llvm-rt*.o instrumentation/*.o diff --git a/gcc_plugin/Makefile b/gcc_plugin/Makefile deleted file mode 100644 index 23477e22..00000000 --- a/gcc_plugin/Makefile +++ /dev/null @@ -1,159 +0,0 @@ -# -# american fuzzy lop++ - GCC plugin instrumentation -# ----------------------------------------------- -# -# Written by Austin Seipp <aseipp@pobox.com> and -# Laszlo Szekeres <lszekeres@google.com> and -# Michal Zalewski and -# Heiko Eißfeldt <heiko@hexco.de> -# -# GCC integration design is based on the LLVM design, which comes -# from Laszlo Szekeres. -# -# Copyright 2015 Google Inc. All rights reserved. -# Copyright 2019-2020 AFLplusplus Project. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# - -PREFIX ?= /usr/local -HELPER_PATH ?= $(PREFIX)/lib/afl -BIN_PATH ?= $(PREFIX)/bin -DOC_PATH ?= $(PREFIX)/share/doc/afl -MAN_PATH ?= $(PREFIX)/share/man/man8 - -VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) -VERSION:sh= grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2 - -CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2 -CFLAGS = -Wall -I../include -Wno-pointer-sign \ - -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ - -DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \ - -Wno-unused-function - -CXXFLAGS = -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2 -CXXEFLAGS = $(CXXFLAGS) -Wall - -CC = gcc -CXX = g++ - -MYCC=$(CC:clang=gcc) -MYCXX=$(CXX:clang++=g++) - -PLUGIN_PATH = $(shell $(MYCC) -print-file-name=plugin) -PLUGIN_PATH:sh= $(MYCC) -print-file-name=plugin -PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(PLUGIN_PATH)/include" -HASH=\# - -GCCVER = $(shell $(MYCC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}') -GCCVER:sh= gcc --version 2>/dev/null | awk 'NR == 1 {print $$NF}' -GCCBINDIR = $(shell dirname `command -v $(MYCC)` 2>/dev/null ) -GCCBINDIR:sh= dirname `command -v $(MYCC)` 2>/dev/null - -_SHMAT_OK= $(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 ) -_SHMAT_OK:sh= echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 - -IGNORE_MMAP=$(TEST_MMAP:1=0) -__SHMAT_OK=$(_SHMAT_OK)$(IGNORE_MMAP) -___SHMAT_OK=$(__SHMAT_OK:10=0) -SHMAT_OK=$(___SHMAT_OK:1=1) -_CFLAGS_ADD=$(SHMAT_OK:1=) -CFLAGS_ADD=$(_CFLAGS_ADD:0=-DUSEMMAP=1) - -_LDFLAGS_ADD=$(SHMAT_OK:1=) -LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt) - -CFLAGS += $(CFLAGS_ADD) -LDFLAGS += $(LDFLAGS_ADD) - -PROGS = ../afl-gcc-pass.so ../afl-gcc-fast ../afl-gcc-rt.o - -all: test_shm test_deps $(PROGS) ../afl-gcc-fast.8 test_build all_done - -debug: - @echo _SHMAT_OK = $(_SHMAT_OK) - @echo IGNORE_MMAP = $(IGNORE_MMAP) - @echo __SHMAT_OK = $(__SHMAT_OK) - @echo ___SHMAT_OK = $(___SHMAT_OK) - @echo SHMAT_OK = $(SHMAT_OK) - -test_shm: - @if [ "$(SHMAT_OK)" == "1" ]; then \ - echo "[+] shmat seems to be working."; \ - rm -f .test2; \ - else \ - echo "[-] shmat seems not to be working, switching to mmap implementation"; \ - fi - -test_deps: - @echo "[*] Checking for working '$(MYCC)'..." - @type $(MYCC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(MYCC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 ) -# @echo "[*] Checking for gcc for plugin support..." -# @$(MYCC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 ) - @echo "[*] Checking for gcc plugin development header files..." - @test -d `$(MYCC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 ) - @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." - -afl-common.o: ../src/afl-common.c - $(MYCC) $(CFLAGS) -c $< -o $@ $(LDFLAGS) - -../afl-gcc-fast: afl-gcc-fast.c afl-common.o - $(MYCC) -DAFL_GCC_CC=\"$(MYCC)\" -DAFL_GCC_CXX=\"$(MYCXX)\" $(CFLAGS) afl-gcc-fast.c afl-common.o -o $@ $(LDFLAGS) - ln -sf afl-gcc-fast ../afl-g++-fast - -../afl-gcc-pass.so: afl-gcc-pass.so.cc - $(MYCXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared afl-gcc-pass.so.cc -o $@ - -../afl-gcc-rt.o: afl-gcc-rt.o.c - $(MYCC) $(CFLAGS) -fPIC -c afl-gcc-rt.o.c -o $@ - -test_build: $(PROGS) - @echo "[*] Testing the CC wrapper and instrumentation output..." - @unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) -# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) - @ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null - @ASAN_OPTIONS=detect_leaks=0 echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr - @rm -f test-instr - @trap 'rm .test-instr0 .test-instr1' 0;if cmp -s .test-instr0 .test-instr1; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi - @echo "[+] All right, the instrumentation seems to be working!" - -all_done: test_build - @echo "[+] All done! You can now use '../afl-gcc-fast' to compile programs." - -.NOTPARALLEL: clean - -../afl-gcc-fast.8: ../afl-gcc-fast - @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@ - @echo .SH NAME >> ../$@ - @echo .B $* >> ../$@ - @echo >> ../$@ - @echo .SH SYNOPSIS >> ../$@ - @../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@ - @echo >> ../$@ - @echo .SH OPTIONS >> ../$@ - @echo .nf >> ../$@ - @../$* -h 2>&1 | tail -n +4 >> ../$@ - @echo >> ../$@ - @echo .SH AUTHOR >> ../$@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@ - @echo >> ../$@ - @echo .SH LICENSE >> ../$@ - @echo Apache License Version 2.0, January 2004 >> ../$@ - ln -sf afl-gcc-fast.8 ../afl-g++-fast.8 - -install: all - install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH) - install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH) - install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md - install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md - -clean: - rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2 - rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8 diff --git a/gcc_plugin/README.instrument_list.md b/gcc_plugin/README.instrument_list.md deleted file mode 100644 index d0eaf6ff..00000000 --- a/gcc_plugin/README.instrument_list.md +++ /dev/null @@ -1,73 +0,0 @@ -======================================== -Using afl++ with partial instrumentation -======================================== - - This file describes how you can selectively instrument only the source files - that are interesting to you using the gcc instrumentation provided by - afl++. - - Plugin by hexcoder-. - - -## 1) Description and purpose - -When building and testing complex programs where only a part of the program is -the fuzzing target, it often helps to only instrument the necessary parts of -the program, leaving the rest uninstrumented. This helps to focus the fuzzer -on the important parts of the program, avoiding undesired noise and -disturbance by uninteresting code being exercised. - -For this purpose, I have added a "partial instrumentation" support to the gcc -plugin of AFLFuzz that allows you to specify on a source file level which files -should be compiled with or without instrumentation. - - -## 2) Building the gcc plugin - -The new code is part of the existing afl++ gcc plugin in the gcc_plugin/ -subdirectory. There is nothing specifically to do :) - - -## 3) How to use the partial instrumentation mode - -In order to build with partial instrumentation, you need to build with -afl-gcc-fast and afl-g++-fast respectively. The only required change is -that you need to set the environment variable AFL_GCC_INSTRUMENT_FILE when calling -the compiler. - -The environment variable must point to a file containing all the filenames -that should be instrumented. For matching, the filename that is being compiled -must end in the filename entry contained in this instrument list (to avoid breaking -the matching when absolute paths are used during compilation). - -For example if your source tree looks like this: - -``` -project/ -project/feature_a/a1.cpp -project/feature_a/a2.cpp -project/feature_b/b1.cpp -project/feature_b/b2.cpp -``` - -and you only want to test feature_a, then create a instrument list file containing: - -``` -feature_a/a1.cpp -feature_a/a2.cpp -``` - -However if the instrument list file contains only this, it works as well: - -``` -a1.cpp -a2.cpp -``` - -but it might lead to files being unwantedly instrumented if the same filename -exists somewhere else in the project directories. - -The created instrument list file is then set to AFL_GCC_INSTRUMENT_FILE when you compile -your program. For each file that didn't match the instrument list, the compiler will -issue a warning at the end stating that no blocks were instrumented. If you -didn't intend to instrument that file, then you can safely ignore that warning. diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c deleted file mode 100644 index b1bacfbd..00000000 --- a/gcc_plugin/afl-gcc-fast.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - american fuzzy lop++ - GCC wrapper for GCC plugin - ------------------------------------------------ - - Written by Austin Seipp <aseipp@pobox.com> and - Laszlo Szekeres <lszekeres@google.com> and - Michal Zalewski - - GCC integration design is based on the LLVM design, which comes - from Laszlo Szekeres. - - Copyright 2015 Google Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This program is a drop-in replacement for gcc, similar in most - respects to ../afl-gcc, but with compiler instrumentation through a - plugin. It tries to figure out compilation mode, adds a bunch of - flags, and then calls the real compiler. - - */ - -#define AFL_MAIN - -#include "config.h" -#include "types.h" -#include "debug.h" -#include "common.h" -#include "alloc-inl.h" - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> - -static u8 * obj_path; /* Path to runtime libraries */ -static u8 **cc_params; /* Parameters passed to the real CC */ -static u32 cc_par_cnt = 1; /* Param count, including argv0 */ -u8 use_stdin = 0; /* dummy */ - -/* Try to find the runtime libraries. If that fails, abort. */ - -static void find_obj(u8 *argv0) { - - u8 *afl_path = getenv("AFL_PATH"); - u8 *slash, *tmp; - - if (afl_path) { - - tmp = alloc_printf("%s/afl-gcc-rt.o", afl_path); - - if (!access(tmp, R_OK)) { - - obj_path = afl_path; - ck_free(tmp); - return; - - } - - ck_free(tmp); - - } - - slash = strrchr(argv0, '/'); - - if (slash) { - - u8 *dir; - - *slash = 0; - dir = ck_strdup(argv0); - *slash = '/'; - - tmp = alloc_printf("%s/afl-gcc-rt.o", dir); - - if (!access(tmp, R_OK)) { - - obj_path = dir; - ck_free(tmp); - return; - - } - - ck_free(tmp); - ck_free(dir); - - } - - if (!access(AFL_PATH "/afl-gcc-rt.o", R_OK)) { - - obj_path = AFL_PATH; - return; - - } - - FATAL( - "Unable to find 'afl-gcc-rt.o' or 'afl-gcc-pass.so'. Please set " - "AFL_PATH"); - -} - -/* Copy argv to cc_params, making the necessary edits. */ - -static void edit_params(u32 argc, char **argv) { - - u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1; - u8 *name; - - cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); - - name = strrchr(argv[0], '/'); - if (!name) - name = argv[0]; - else - ++name; - - if (!strcmp(name, "afl-g++-fast")) { - - u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX; - - } else if (!strcmp(name, "afl-gcc-fast")) { - - u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC; - - } else { - - fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL( - "Name of the binary is not a known name, expected afl-(gcc|g++)-fast"); - - } - - char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path); - cc_params[cc_par_cnt++] = fplugin_arg; - - /* Detect stray -v calls from ./configure scripts. */ - - if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0; - - while (--argc) { - - u8 *cur = *(++argv); - -#if defined(__x86_64__) - if (!strcmp(cur, "-m32")) FATAL("-m32 is not supported"); -#endif - - if (!strcmp(cur, "-x")) x_set = 1; - - if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E") || - !strcmp(cur, "-v")) - maybe_linking = 0; - - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) - asan_set = 1; - - if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; - - if (!strcmp(cur, "-shared")) maybe_linking = 0; - - cc_params[cc_par_cnt++] = cur; - - } - - if (getenv("AFL_HARDEN")) { - - cc_params[cc_par_cnt++] = "-fstack-protector-all"; - - if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; - - } - - if (!asan_set) { - - if (getenv("AFL_USE_ASAN")) { - - if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive"); - - if (getenv("AFL_HARDEN")) - FATAL("ASAN and AFL_HARDEN are mutually exclusive"); - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=address"; - - } else if (getenv("AFL_USE_MSAN")) { - - if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive"); - - if (getenv("AFL_HARDEN")) - FATAL("MSAN and AFL_HARDEN are mutually exclusive"); - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=memory"; - - } - - } - - if (getenv("AFL_USE_UBSAN")) { - - cc_params[cc_par_cnt++] = "-fsanitize=undefined"; - cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error"; - cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all"; - - } - - if (!getenv("AFL_DONT_OPTIMIZE")) { - - cc_params[cc_par_cnt++] = "-g"; - cc_params[cc_par_cnt++] = "-O3"; - cc_params[cc_par_cnt++] = "-funroll-loops"; - - } - - if (getenv("AFL_NO_BUILTIN")) { - - cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; - - } - -#if defined(USEMMAP) && !defined(__HAIKU__) - 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"; - - /* When the user tries to use persistent or deferred forkserver modes by - appending a single line to the program, we want to reliably inject a - signature into the binary (to be picked up by afl-fuzz) and we want - to call a function from the runtime .o file. This is unnecessarily - painful for three reasons: - - 1) We need to convince the compiler not to optimize out the signature. - This is done with __attribute__((used)). - - 2) We need to convince the linker, when called with -Wl,--gc-sections, - not to do the same. This is done by forcing an assignment to a - 'volatile' pointer. - - 3) We need to declare __afl_persistent_loop() in the global namespace, - but doing this within a method in a class is hard - :: and extern "C" - are forbidden and __attribute__((alias(...))) doesn't work. Hence the - __asm__ aliasing trick. - - */ - - cc_params[cc_par_cnt++] = - "-D__AFL_LOOP(_A)=" - "({ static volatile char *_B __attribute__((used)); " - " _B = (char*)\"" PERSIST_SIG - "\"; " -#ifdef __APPLE__ - "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " -#else - "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " -#endif /* ^__APPLE__ */ - "_L(_A); })"; - - cc_params[cc_par_cnt++] = - "-D__AFL_INIT()=" - "do { static volatile char *_A __attribute__((used)); " - " _A = (char*)\"" DEFER_SIG - "\"; " -#ifdef __APPLE__ - "void _I(void) __asm__(\"___afl_manual_init\"); " -#else - "void _I(void) __asm__(\"__afl_manual_init\"); " -#endif /* ^__APPLE__ */ - "_I(); } while (0)"; - - if (maybe_linking) { - - if (x_set) { - - cc_params[cc_par_cnt++] = "-x"; - cc_params[cc_par_cnt++] = "none"; - - } - - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-gcc-rt.o", obj_path); - - } - - cc_params[cc_par_cnt] = NULL; - -} - -/* Main entry point */ - -int main(int argc, char **argv, char **envp) { - - if (argc < 2 || strcmp(argv[1], "-h") == 0) { - - printf(cCYA - "afl-gcc-fast" VERSION cRST - " initially by <aseipp@pobox.com>, maintainer: hexcoder-\n" - "\n" - "afl-gcc-fast [options]\n" - "\n" - "This is a helper application for afl-fuzz. It serves as a drop-in " - "replacement\n" - "for gcc, letting you recompile third-party code with the required " - "runtime\n" - "instrumentation. A common use pattern would be one of the " - "following:\n\n" - - " CC=%s/afl-gcc-fast ./configure\n" - " CXX=%s/afl-g++-fast ./configure\n\n" - - "In contrast to the traditional afl-gcc tool, this version is " - "implemented as\n" - "a GCC plugin and tends to offer improved performance with slow " - "programs\n" - "(similarly to the LLVM plugin used by afl-clang-fast).\n\n" - - "Environment variables used:\n" - "AFL_CC: path to the C compiler to use\n" - "AFL_CXX: path to the C++ compiler to use\n" - "AFL_PATH: path to instrumenting pass and runtime (afl-gcc-rt.*o)\n" - "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" - "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" - "AFL_INST_RATIO: percentage of branches to instrument\n" - "AFL_QUIET: suppress verbose output\n" - "AFL_DEBUG: enable developer debugging output\n" - "AFL_HARDEN: adds code hardening to catch memory bugs\n" - "AFL_USE_ASAN: activate address sanitizer\n" - "AFL_USE_MSAN: activate memory sanitizer\n" - "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" - "AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by " - "filename\n" - - "\nafl-gcc-fast was built for gcc %s with the gcc binary path of " - "\"%s\".\n\n", - BIN_PATH, BIN_PATH, GCC_VERSION, GCC_BINDIR); - - exit(1); - - } else if ((isatty(2) && !getenv("AFL_QUIET")) || - - getenv("AFL_DEBUG") != NULL) { - - SAYF(cCYA "afl-gcc-fast" VERSION cRST - " initially by <aseipp@pobox.com>, maintainer: hexcoder-\n"); - - if (getenv("AFL_GCC_INSTRUMENT_FILE") == NULL && - getenv("AFL_GCC_WHITELIST") == NULL) { - - SAYF( - cYEL - "Warning:" cRST - " using afl-gcc-fast without using AFL_GCC_INSTRUMENT_FILE currently " - "produces worse results than afl-gcc. Even better, use " - "llvm_mode for now.\n"); - - } - - } else - - be_quiet = 1; - - u8 *ptr; - if (!be_quiet && - ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) { - - u32 map_size = atoi(ptr); - if (map_size != MAP_SIZE) - WARNF("AFL_MAP_SIZE is not supported by afl-gcc-fast"); - - } - - check_environment_vars(envp); - - find_obj(argv[0]); - - edit_params(argc, argv); - /*if (isatty(2) && !getenv("AFL_QUIET")) { - - printf("Calling \"%s\" with:\n", cc_params[0]); - for(int i=1; i<cc_par_cnt; i++) printf("%s\n", cc_params[i]); - - } - - */ - execvp(cc_params[0], (char **)cc_params); - - FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); - - return 0; - -} - diff --git a/gcc_plugin/afl-gcc-rt.o.c b/gcc_plugin/afl-gcc-rt.o.c deleted file mode 100644 index 49a03cae..00000000 --- a/gcc_plugin/afl-gcc-rt.o.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - american fuzzy lop++ - GCC plugin instrumentation bootstrap - --------------------------------------------------------- - - Written by Austin Seipp <aseipp@pobox.com> and - Laszlo Szekeres <lszekeres@google.com> and - Michal Zalewski - - GCC integration design is based on the LLVM design, which comes - from Laszlo Szekeres. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This code is the rewrite of afl-as.h's main_payload. - -*/ - -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif -#include "../config.h" -#include "../types.h" - -#ifdef USEMMAP - #include <stdio.h> -#endif -#include <stdlib.h> -#include <signal.h> -#include <unistd.h> -#include <string.h> -#include <assert.h> - -#include <sys/mman.h> -#ifndef USEMMAP - #include <sys/shm.h> -#endif -#include <sys/wait.h> -#include <sys/types.h> - -#include <sys/mman.h> -#include <fcntl.h> - -/* Globals needed by the injected instrumentation. The __afl_area_initial region - is used for instrumentation output before __afl_map_shm() has a chance to - run. It will end up as .comm, so it shouldn't be too wasteful. */ - -u8 __afl_area_initial[MAP_SIZE]; -u8 *__afl_area_ptr = __afl_area_initial; - -#ifdef __ANDROID__ -u32 __afl_prev_loc; -u32 __afl_final_loc; -#else -__thread u32 __afl_prev_loc; -__thread u32 __afl_final_loc; -#endif - -/* Trace a basic block with some ID */ -void __afl_trace(const u32 x) { - -#if 1 /* enable for neverZero feature. */ - __afl_area_ptr[__afl_prev_loc ^ x] += - 1 + ((u8)(1 + __afl_area_ptr[__afl_prev_loc ^ x]) == 0); -#else - ++__afl_area_ptr[__afl_prev_loc ^ x]; -#endif - - __afl_prev_loc = (x >> 1); - return; - -} - -/* Running in persistent mode? */ - -static u8 is_persistent; - -/* SHM setup. */ - -static void __afl_map_shm(void) { - - u8 *id_str = getenv(SHM_ENV_VAR); - - /* If we're running under AFL, attach to the appropriate region, replacing the - early-stage __afl_area_initial region that is needed to allow some really - hacky .init code to work correctly in projects such as OpenSSL. */ - - if (id_str) { - -#ifdef USEMMAP - const char * shm_file_path = id_str; - int shm_fd = -1; - unsigned char *shm_base = NULL; - - /* create the shared memory segment as if it was a file */ - shm_fd = shm_open(shm_file_path, O_RDWR, 0600); - if (shm_fd == -1) { - - fprintf(stderr, "shm_open() failed\n"); - exit(1); - - } - - /* map the shared memory segment to the address space of the process */ - shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shm_base == MAP_FAILED) { - - close(shm_fd); - shm_fd = -1; - - fprintf(stderr, "mmap() failed\n"); - exit(2); - - } - - __afl_area_ptr = shm_base; -#else - u32 shm_id = atoi(id_str); - - __afl_area_ptr = shmat(shm_id, NULL, 0); -#endif - - /* Whooooops. */ - - if (__afl_area_ptr == (void *)-1) exit(1); - - /* Write something into the bitmap so that even with low AFL_INST_RATIO, - our parent doesn't give up on us. */ - - __afl_area_ptr[0] = 1; - - } - -} - -/* Fork server logic. */ - -static void __afl_start_forkserver(void) { - - u8 tmp[4] = {0, 0, 0, 0}; - u32 map_size = MAP_SIZE; - s32 child_pid; - - u8 child_stopped = 0; - - void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL); - - /* Phone home and tell the parent that we're OK. If parent isn't there, - assume we're not running in forkserver mode and just execute program. */ - - if (MAP_SIZE <= 0x800000) { - - map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE)); - memcpy(tmp, &map_size, 4); - - } - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; - - while (1) { - - u32 was_killed; - int status; - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - - if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(1); - - /* If we stopped the child in persistent mode, but there was a race - condition and afl-fuzz already issued SIGKILL, write off the old - process. */ - - if (child_stopped && was_killed) { - - child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) exit(1); - - } - - if (!child_stopped) { - - /* Once woken up, create a clone of our process. */ - - child_pid = fork(); - if (child_pid < 0) exit(1); - - /* In child process: close fds, resume execution. */ - - if (!child_pid) { - - signal(SIGCHLD, old_sigchld_handler); - - close(FORKSRV_FD); - close(FORKSRV_FD + 1); - return; - - } - - } else { - - /* Special handling for persistent mode: if the child is alive but - currently stopped, simply restart it with SIGCONT. */ - - kill(child_pid, SIGCONT); - child_stopped = 0; - - } - - /* In parent process: write PID to pipe, then wait for child. */ - - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(1); - - if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) exit(1); - - /* In persistent mode, the child stops itself with SIGSTOP to indicate - a successful run. In this case, we want to wake it up without forking - again. */ - - if (WIFSTOPPED(status)) child_stopped = 1; - - /* Relay wait status to pipe, then loop back. */ - - if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); - - } - -} - -/* A simplified persistent mode handler, used as explained in README.md. */ - -int __afl_persistent_loop(unsigned int max_cnt) { - - static u8 first_pass = 1; - static u32 cycle_cnt; - - if (first_pass) { - - /* Make sure that every iteration of __AFL_LOOP() starts with a clean slate. - On subsequent calls, the parent will take care of that, but on the first - iteration, it's our job to erase any trace of whatever happened - before the loop. */ - - if (is_persistent) { - - memset(__afl_area_ptr, 0, MAP_SIZE); - __afl_area_ptr[0] = 1; - __afl_prev_loc = 0; - - } - - cycle_cnt = max_cnt; - first_pass = 0; - return 1; - - } - - if (is_persistent) { - - if (--cycle_cnt) { - - raise(SIGSTOP); - - __afl_area_ptr[0] = 1; - __afl_prev_loc = 0; - - return 1; - - } else { - - /* When exiting __AFL_LOOP(), make sure that the subsequent code that - follows the loop is not traced. We do that by pivoting back to the - dummy output region. */ - - __afl_area_ptr = __afl_area_initial; - - } - - } - - return 0; - -} - -/* This one can be called from user code when deferred forkserver mode - is enabled. */ - -void __afl_manual_init(void) { - - static u8 init_done; - - if (!init_done) { - - __afl_map_shm(); - __afl_start_forkserver(); - init_done = 1; - - } - -} - -/* Proper initialization routine. */ - -__attribute__((constructor(101))) void __afl_auto_init(void) { - - is_persistent = !!getenv(PERSIST_ENV_VAR); - - if (getenv(DEFER_ENV_VAR)) return; - - __afl_manual_init(); - -} - diff --git a/llvm_mode/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc index 61a420ba..61a420ba 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/instrumentation/LLVMInsTrim.so.cc diff --git a/llvm_mode/MarkNodes.cc b/instrumentation/MarkNodes.cc index 20a7df35..20a7df35 100644 --- a/llvm_mode/MarkNodes.cc +++ b/instrumentation/MarkNodes.cc diff --git a/llvm_mode/MarkNodes.h b/instrumentation/MarkNodes.h index 8ddc978d..8ddc978d 100644 --- a/llvm_mode/MarkNodes.h +++ b/instrumentation/MarkNodes.h diff --git a/llvm_mode/README.cmplog.md b/instrumentation/README.cmplog.md index 7f426ec8..5f855e1f 100644 --- a/llvm_mode/README.cmplog.md +++ b/instrumentation/README.cmplog.md @@ -30,7 +30,7 @@ cp ./program ./program.cmplog ## Use -AFL++ has the new -c option that can be used to specify a CmpLog binary (the second +AFL++ has the new -c option that needs to be used to specify the CmpLog binary (the second build). For example: @@ -39,4 +39,4 @@ For example: afl-fuzz -i input -o output -c ./program.cmplog -m none -- ./program.afl @@ ``` -Be careful to use -m none because CmpLog maps a lot of pages. +Be sure to use `-m none` because CmpLog can map a lot of pages. diff --git a/llvm_mode/README.ctx.md b/instrumentation/README.ctx.md index 14255313..caf2c09a 100644 --- a/llvm_mode/README.ctx.md +++ b/instrumentation/README.ctx.md @@ -4,7 +4,7 @@ This is an LLVM-based implementation of the context sensitive branch coverage. -Basically every function gets it's own ID and that ID is combined with the +Basically every function gets its own ID and that ID is combined with the edges of the called functions. So if both function A and function B call a function C, the coverage diff --git a/gcc_plugin/README.md b/instrumentation/README.gcc_plugin.md index f762131e..9d6bc200 100644 --- a/gcc_plugin/README.md +++ b/instrumentation/README.gcc_plugin.md @@ -1,7 +1,7 @@ # GCC-based instrumentation for afl-fuzz (See [../README.md](../README.md) for the general instruction manual.) - (See [../llvm_mode/README.md](../llvm_mode/README.md) for the LLVM-based instrumentation.) + (See [README.llvm.md](README.llvm.md) for the LLVM-based instrumentation.) !!! TODO items are: !!! => inline instrumentation has to work! diff --git a/instrumentation/README.instrim.md b/instrumentation/README.instrim.md new file mode 100644 index 00000000..99f6477a --- /dev/null +++ b/instrumentation/README.instrim.md @@ -0,0 +1,30 @@ +# InsTrim + +InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing + +## Introduction + +InsTrim is the work of Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang. + +It uses a CFG (call flow graph) and markers to instrument just what +is necessary in the binary (ie less than llvm_mode). As a result the binary is +about 10-15% faster compared to normal llvm_mode however with some coverage loss. +It requires at least llvm version 3.8.0 to build. +If you have LLVM 7+ we recommend PCGUARD instead. + +## Usage + +Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1` +during compilation of the target. + +There is also special mode which instruments loops in a way so that +afl-fuzz can see which loop path has been selected but not being able to +see how often the loop has been rerun. +This again is a tradeoff for speed for less path information. +To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`. + +## Background + +The paper from Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang: +[InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing] +(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf) diff --git a/llvm_mode/README.instrument_list.md b/instrumentation/README.instrument_list.md index 1fc06414..60474ec6 100644 --- a/llvm_mode/README.instrument_list.md +++ b/instrumentation/README.instrument_list.md @@ -1,8 +1,8 @@ # Using afl++ with partial instrumentation - This file describes how you can selectively instrument only the source files - or functions that are interesting to you using the LLVM instrumentation - provided by afl++ + This file describes how to selectively instrument only source files + or functions that are of interest to you using the LLVM instrumentation + provided by afl++. ## 1) Description and purpose @@ -13,10 +13,10 @@ on the important parts of the program, avoiding undesired noise and disturbance by uninteresting code being exercised. For this purpose, a "partial instrumentation" support en par with llvm sancov -is provided by afl++ that allows you to specify on a source file and function +is provided by afl++ that allows to specify on a source file and function level which function should be compiled with or without instrumentation. -Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead: +Note: When using PCGUARD mode - and llvm 12+ - you can use this instead: https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation The llvm sancov list format is fully supported by afl++, however afl++ has @@ -24,8 +24,8 @@ more flexibility. ## 2) Building the LLVM module -The new code is part of the existing afl++ LLVM module in the llvm_mode/ -subdirectory. There is nothing specifically to do :) +The new code is part of the existing afl++ LLVM module in the instrumentation/ +subdirectory. There is nothing specifically to do for the build :) ## 3) How to use the partial instrumentation mode @@ -34,14 +34,14 @@ afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++. The only required change is that you need to set either the environment variable AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename. -That file then contains the filenames or functions that should be instrumented -(AFL_LLVM_ALLOWLIST) or should specifically NOT be instrumented (AFL_LLVM_DENYLIST). +That file should contain the file names or functions that are to be instrumented +(AFL_LLVM_ALLOWLIST) or are specifically NOT to be instrumented (AFL_LLVM_DENYLIST). -For matching, the function/filename that is being compiled must end in the -function/filename entry contained in this instrument file list (to avoid -breaking the matching when absolute paths are used during compilation). +For matching to succeed, the function/file name that is being compiled must end in the +function/file name entry contained in this instrument file list. That is to avoid +breaking the match when absolute paths are used during compilation. -**NOTE:** In builds with optimization enabled functions might be inlined and would not match! +**NOTE:** In builds with optimization enabled, functions might be inlined and would not match! For example if your source tree looks like this: ``` @@ -52,13 +52,13 @@ project/feature_b/b1.cpp project/feature_b/b2.cpp ``` -and you only want to test feature_a, then create a instrument file list file containing: +and you only want to test feature_a, then create an "instrument file list" file containing: ``` feature_a/a1.cpp feature_a/a2.cpp ``` -However if the instrument file list file contains only this, it works as well: +However if the "instrument file list" file contains only this, it works as well: ``` a1.cpp a2.cpp @@ -67,9 +67,9 @@ but it might lead to files being unwantedly instrumented if the same filename exists somewhere else in the project directories. You can also specify function names. Note that for C++ the function names -must be mangled to match! +must be mangled to match! `nm` can print these names. -afl++ is able to identify if an entry is a filename or a function. +afl++ is able to identify whether an entry is a filename or a function. However if you want to be sure (and compliant to the sancov allow/blocklist format), you can specify source file entries like this: ``` @@ -82,5 +82,6 @@ fun: MallocFoo Note that whitespace is ignored and comments (`# foo`) are supported. ## 4) UNIX-style pattern matching -You can add UNIX-style pattern matching in the the instrument file list entries. + +You can add UNIX-style pattern matching in the "instrument file list" entries. See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/llvm_mode/README.laf-intel.md b/instrumentation/README.laf-intel.md index f63ab2bb..c50a6979 100644 --- a/llvm_mode/README.laf-intel.md +++ b/instrumentation/README.laf-intel.md @@ -1,5 +1,15 @@ # laf-intel instrumentation +## Introduction + +This originally is the work of an individual nicknamed laf-intel. +His blog [Circumventing Fuzzing Roadblocks with Compiler Transformations] +(https://lafintel.wordpress.com/) and gitlab repo [laf-llvm-pass] +(https://gitlab.com/laf-intel/laf-llvm-pass/) +describe some code transformations that +help afl++ to enter conditional blocks, where conditions consist of +comparisons of large values. + ## Usage By default these passes will not run when you compile programs using @@ -24,18 +34,22 @@ Enables the split-compares pass. By default it will 1. simplify operators >= (and <=) into chains of > (<) and == comparisons 2. change signed integer comparisons to a chain of sign-only comparison -and unsigned comparisons +and unsigned integer comparisons 3. split all unsigned integer comparisons with bit widths of 64, 32 or 16 bits to chains of 8 bits comparisons. You can change the behaviour of the last step by setting `export AFL_LLVM_LAF_SPLIT_COMPARES_BITW=<bit_width>`, where -bit_width may be 64, 32 or 16. +bit_width may be 64, 32 or 16. For example, a bit_width of 16 +would split larger comparisons down to 16 bit comparisons. A new experimental feature is splitting floating point comparisons into a series of sign, exponent and mantissa comparisons followed by splitting each of them into 8 bit comparisons when necessary. It is activated with the `AFL_LLVM_LAF_SPLIT_FLOATS` setting. +Please note that full IEEE 754 functionality is not preserved, that is +values of nan and infinity will probably behave differently. + Note that setting this automatically activates `AFL_LLVM_LAF_SPLIT_COMPARES` You can also set `AFL_LLVM_LAF_ALL` and have all of the above enabled :-) diff --git a/llvm_mode/README.md b/instrumentation/README.llvm.md index f23d7150..51e9995b 100644 --- a/llvm_mode/README.md +++ b/instrumentation/README.llvm.md @@ -1,8 +1,8 @@ # Fast LLVM-based instrumentation for afl-fuzz - (See [../README](../README.md) for the general instruction manual.) + (See [../README.md](../README.md) for the general instruction manual.) - (See [../gcc_plugin/README](../gcc_plugin/README.md) for the GCC-based instrumentation.) + (See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) ## 1) Introduction @@ -93,15 +93,16 @@ operating mode of AFL, e.g.: Be sure to also include CXX set to afl-clang-fast++ for C++ code. +Note that afl-clang-fast/afl-clang-fast++ are just pointers to afl-cc. +You can also use afl-cc/afl-c++ and instead direct it to use LLVM +instrumentation by either setting `AFL_CC_COMPILER=LLVM` or pass the parameter +`--afl-llvm` via CFLAGS/CXXFLAGS/CPPFLAGS. + The tool honors roughly the same environmental variables as afl-gcc (see [docs/env_variables.md](../docs/env_variables.md)). This includes AFL_USE_ASAN, AFL_HARDEN, and AFL_DONT_OPTIMIZE. However AFL_INST_RATIO is not honored -as it does not serve a good purpose with the more effective instrim CFG -analysis. - -Note: if you want the LLVM helper to be installed on your system for all -users, you need to build it before issuing 'make install' in the parent -directory. +as it does not serve a good purpose with the more effective PCGUARD, LTO and + instrim CFG analysis. ## 3) Options @@ -109,9 +110,9 @@ Several options are present to make llvm_mode faster or help it rearrange the code to make afl-fuzz path discovery easier. If you need just to instrument specific parts of the code, you can the instrument file list -which C/C++ files to actually instrument. See [README.instrument_list](README.instrument_list.md) +which C/C++ files to actually instrument. See [README.instrument_list.md](README.instrument_list.md) -For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md) +For splitting memcmp, strncmp, etc. please see [README.laf-intel.md](README.laf-intel.md) Then there are different ways of instrumenting the target: @@ -119,42 +120,42 @@ Then there are different ways of instrumenting the target: markers to just instrument what is needed. This increases speed by 10-15% without any disadvantages If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1 -See [README.instrim](README.instrim.md) +See [README.instrim.md](README.instrim.md) 2. An even better instrumentation strategy uses LTO and link time instrumentation. Note that not all targets can compile in this mode, however if it works it is the best option you can use. Simply use afl-clang-lto/afl-clang-lto++ to use this option. -See [README.lto](README.lto.md) +See [README.lto.md](README.lto.md) 3. Alternativly you can choose a completely different coverage method: 3a. N-GRAM coverage - which combines the previous visited edges with the current one. This explodes the map but on the other hand has proven to be effective for fuzzing. -See [README.ngram](README.ngram.md) +See [README.ngram.md](README.ngram.md) 3b. Context sensitive coverage - which combines the visited edges with an individual caller ID (the function that called the current one) -[README.ctx](README.ctx.md) +[README.ctx.md](README.ctx.md) Then - additionally to one of the instrumentation options above - there is a very effective new instrumentation option called CmpLog as an alternative to laf-intel that allow AFL++ to apply mutations similar to Redqueen. -See [README.cmplog](README.cmplog.md) +See [README.cmplog.md](README.cmplog.md) 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 x86 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](README.neverzero.md) +See [README.neverzero.md](README.neverzero.md) ## 4) Snapshot feature To speed up fuzzing you can use a linux loadable kernel module which enables a snapshot feature. -See [README.snapshot](README.snapshot.md) +See [README.snapshot.md](README.snapshot.md) ## 5) Gotchas, feedback, bugs @@ -182,5 +183,12 @@ targets this way: AFL_LLVM_INSTRUMENT=PCGUARD make ``` -Note that this us currently the default, as it is the best mode. +Note that this us currently the default if you use LLVM >= 7, as it is the best +mode. Recommended is LLVM >= 9. If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode. + +## 8) Bonus feature: 'dict2file' pass + +Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation +all constant string compare parameters will be written to this file to be +used with afl-fuzz' `-x` option. diff --git a/llvm_mode/README.lto.md b/instrumentation/README.lto.md index 9046c5a8..abdbd2ac 100644 --- a/llvm_mode/README.lto.md +++ b/instrumentation/README.lto.md @@ -95,10 +95,7 @@ export PATH=`pwd`/bin:$PATH export LLVM_CONFIG=`pwd`/bin/llvm-config cd /path/to/AFLplusplus/ make -cd llvm_mode -make -cd .. -make install +sudo make install ``` ## How to use afl-clang-lto @@ -115,18 +112,18 @@ make ``` NOTE: some targets also need to set the linker, try both `afl-clang-lto` and -`afl-ld-lto` for this for `LD=` for `configure`. +`afl-ld-lto` for `LD=` before `configure`. ## AUTODICTIONARY feature -While compiling, automatically a dictionary based on string comparisons is -generated put into the target binary. This dictionary is transfered to afl-fuzz +While compiling, a dictionary based on string comparisons is automatically +generated and put into the target binary. This dictionary is transfered to afl-fuzz on start. This improves coverage statistically by 5-10% :) ## Fixed memory map To speed up fuzzing, it is possible to set a fixed shared memory map. -Recommened is the value 0x10000. +Recommended is the value 0x10000. In most cases this will work without any problems. However if a target uses early constructors, ifuncs or a deferred forkserver this can crash the target. On unusual operating systems/processors/kernels or weird libraries this might @@ -136,14 +133,14 @@ to be dynamic - the original afl way, which is slower). ## Document edge IDs -Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge +Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document in a file which edge ID was given to which function. This helps to identify functions with variable bytes or which functions were touched by an input. ## Solving difficult targets Some targets are difficult because the configure script does unusual stuff that -is unexpected for afl. See the next chapter `Potential issues` how to solve +is unexpected for afl. See the next chapter `Potential issues` for how to solve these. ### Example: ffmpeg @@ -151,7 +148,7 @@ these. An example of a hard to solve target is ffmpeg. Here is how to successfully instrument it: -1. Get and extract the current ffmpeg and change to it's directory +1. Get and extract the current ffmpeg and change to its directory 2. Running configure with --cc=clang fails and various other items will fail when compiling, so we have to trick configure: @@ -221,13 +218,13 @@ If you see this message: /bin/ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one ``` This is because usually gnu gcc ranlib is being called which cannot deal with clang LTO files. -The solution is simple: when you ./configure you have also have to set RANLIB=llvm-ranlib and AR=llvm-ar +The solution is simple: when you ./configure you also have to set RANLIB=llvm-ranlib and AR=llvm-ar Solution: ``` AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared ``` -and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it. +and on some targets you have to set AR=/RANLIB= even for make as the configure script does not save it. Other targets ignore environment variables and need the parameters set via `./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!). @@ -246,8 +243,8 @@ AS=llvm-as ... afl-clang-lto is still work in progress. Known issues: - * Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously - * Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously + * Anything that llvm 11+ cannot compile, afl-clang-lto cannot compile either - obviously + * Anything that does not compile with LTO, afl-clang-lto cannot compile either - obviously Hence if building a target with afl-clang-lto fails try to build it with llvm12 and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and @@ -267,14 +264,14 @@ for this in the PassManager: EP_FullLinkTimeOptimizationLast ("Fun" info - nobody knows what this is doing. And the developer who implemented this didn't respond to emails.) -In December came then the idea to implement this as a pass that is run via +In December then came the idea to implement this as a pass that is run via the llvm "opt" program, which is performed via an own linker that afterwards calls the real linker. This was first implemented in January and work ... kinda. -The LTO time instrumentation worked, however the "how" the basic blocks were +The LTO time instrumentation worked, however "how" the basic blocks were instrumented was a problem, as reducing duplicates turned out to be very, very difficult with a program that has so many paths and therefore so many -dependencies. At lot of strategies were implemented - and failed. +dependencies. A lot of strategies were implemented - and failed. And then sat solvers were tried, but with over 10.000 variables that turned out to be a dead-end too. diff --git a/llvm_mode/README.neverzero.md b/instrumentation/README.neverzero.md index 903e5bd3..5c894d6e 100644 --- a/llvm_mode/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -2,8 +2,8 @@ ## Usage -In larger, complex or reiterative programs the counters that collect the edge -coverage can easily fill up and wrap around. +In larger, complex or reiterative programs the byte sized counters that collect +the edge coverage can easily fill up and wrap around. This is not that much of an issue - unless by chance it wraps just to a value of zero when the program execution ends. In this case afl-fuzz is not able to see that the edge has been accessed and diff --git a/llvm_mode/README.ngram.md b/instrumentation/README.ngram.md index de3ba432..de3ba432 100644 --- a/llvm_mode/README.ngram.md +++ b/instrumentation/README.ngram.md diff --git a/llvm_mode/README.persistent_mode.md b/instrumentation/README.persistent_mode.md index 7d2fd93b..e095f036 100644 --- a/llvm_mode/README.persistent_mode.md +++ b/instrumentation/README.persistent_mode.md @@ -4,11 +4,11 @@ The most effective way is to fuzz in persistent mode, as the speed can easily be x10 or x20 times faster without any disadvanges. -*All professionel fuzzing is using this mode.* +*All professional fuzzing is using this mode.* This requires that the target can be called in a (or several) function(s), -and that the state can be resetted so that multiple calls be be performed -without memory leaking and former runs having no impact on following runs +and that its state can be resetted so that multiple calls can be performed +without resource leaks and former runs having no impact on following runs (this can be seen by the `stability` indicator in the `afl-fuzz` UI). Examples can be found in [examples/persistent_mode](../examples/persistent_mode). @@ -67,7 +67,7 @@ add this just after the includes: #endif ``` -## 3) deferred initialization +## 3) Deferred initialization AFL tries to optimize performance by executing the targeted binary just once, stopping it just before main(), and then cloning this "main" process to get @@ -112,7 +112,7 @@ With the location selected, add this code in the appropriate spot: You don't need the #ifdef guards, but including them ensures that the program will keep working normally when compiled with a tool other than afl-clang-fast. -Finally, recompile the program with afl-clang-fast (afl-gcc or afl-clang will +Finally, recompile the program with afl-clang-fast/lto (afl-gcc or afl-clang will *not* generate a deferred-initialization binary) - and you should be all set! *NOTE:* In the code between `main` and `__AFL_INIT()` should not be any code @@ -142,7 +142,7 @@ and just before `__AFL_INIT()`: __afl_area_ptr = NULL; ``` -## 4) persistent mode +## 4) Persistent mode Some libraries provide APIs that are stateless, or whose state can be reset in between processing different input files. When such a reset is performed, a @@ -183,7 +183,7 @@ PS. Because there are task switches still involved, the mode isn't as fast as faster than the normal fork() model, and compared to in-process fuzzing, should be a lot more robust. -## 5) shared memory fuzzing +## 5) Shared memory fuzzing You can speed up the fuzzing process even more by receiving the fuzzing data via shared memory instead of stdin or files. diff --git a/llvm_mode/README.snapshot.md b/instrumentation/README.snapshot.md index 9c12a8ba..c40a956a 100644 --- a/llvm_mode/README.snapshot.md +++ b/instrumentation/README.snapshot.md @@ -1,7 +1,7 @@ # AFL++ snapshot feature Snapshotting is a feature that makes a snapshot from a process and then -restores it's state, which is faster then forking it again. +restores its state, which is faster then forking it again. All targets compiled with llvm_mode are automatically enabled for the snapshot feature. diff --git a/llvm_mode/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 1dd65188..1dd65188 100644 --- a/llvm_mode/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc diff --git a/llvm_mode/afl-llvm-rt.o.c b/instrumentation/afl-compiler-rt.o.c index bdafbe0b..a3d75b15 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1,11 +1,6 @@ /* - american fuzzy lop++ - LLVM instrumentation bootstrap - --------------------------------------------------- - - Written by Laszlo Szekeres <lszekeres@google.com> and - Michal Zalewski - - LLVM integration design comes from Laszlo Szekeres. + american fuzzy lop++ - instrumentation bootstrap + ------------------------------------------------ Copyright 2015, 2016 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. All rights reserved. @@ -16,7 +11,6 @@ http://www.apache.org/licenses/LICENSE-2.0 - This code is the rewrite of afl-as.h's main_payload. */ @@ -111,6 +105,22 @@ static u8 is_persistent; static u8 _is_sancov; +/* Uninspired gcc plugin instrumentation */ + +void __afl_trace(const u32 x) { + +#if 1 /* enable for neverZero feature. */ + __afl_area_ptr[__afl_prev_loc[0] ^ x] += + 1 + ((u8)(1 + __afl_area_ptr[__afl_prev_loc[0] ^ x]) == 0); +#else + ++__afl_area_ptr[__afl_prev_loc[0] ^ x]; +#endif + + __afl_prev_loc[0] = (x >> 1); + return; + +} + /* Error reporting to forkserver controller */ void send_forkserver_error(int error) { @@ -808,7 +818,7 @@ static void __afl_start_forkserver(void) { } /* A simplified persistent mode handler, used as explained in - * llvm_mode/README.md. */ + * README.llvm.md. */ int __afl_persistent_loop(unsigned int max_cnt) { @@ -958,7 +968,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { /* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard. It remains non-operational in the traditional, plugin-backed LLVM mode. - For more info about 'trace-pc-guard', see llvm_mode/README.md. + For more info about 'trace-pc-guard', see README.llvm.md. The first function (__sanitizer_cov_trace_pc_guard) is called back on every edge (as opposed to every basic block). */ diff --git a/gcc_plugin/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index c5614aca..c5614aca 100644 --- a/gcc_plugin/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc diff --git a/llvm_mode/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 189b4ec6..189b4ec6 100644 --- a/llvm_mode/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc diff --git a/llvm_mode/afl-llvm-common.h b/instrumentation/afl-llvm-common.h index a1561d9c..a1561d9c 100644 --- a/llvm_mode/afl-llvm-common.h +++ b/instrumentation/afl-llvm-common.h diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc new file mode 100644 index 00000000..e87ecce8 --- /dev/null +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -0,0 +1,599 @@ +/* + american fuzzy lop++ - LLVM LTO instrumentation pass + ---------------------------------------------------- + + Written by Marc Heuse <mh@mh-sec.de> + + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This library is plugged into LLVM when invoking clang through afl-clang-lto. + + */ + +#define AFL_LLVM_PASS + +#include "config.h" +#include "debug.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> + +#include <list> +#include <string> +#include <fstream> +#include <set> + +#include "llvm/Config/llvm-config.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/MemorySSAUpdater.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Pass.h" +#include "llvm/IR/Constants.h" + +#include "afl-llvm-common.h" + +#ifndef O_DSYNC + #define O_DSYNC O_SYNC +#endif + +using namespace llvm; + +namespace { + +class AFLdict2filePass : public ModulePass { + + public: + static char ID; + + AFLdict2filePass() : ModulePass(ID) { + + if (getenv("AFL_DEBUG")) debug = 1; + + } + + bool runOnModule(Module &M) override; + +}; + +} // namespace + +void dict2file(int fd, u8 *mem, u32 len) { + + int i, j, binary = 0; + char line[MAX_AUTO_EXTRA * 8], tmp[8]; + + strcpy(line, "\""); + j = 1; + for (i = 0; i < len; i++) { + + if (isprint(mem[i])) { + + line[j++] = mem[i]; + + } else { + + if (i + 1 != len || mem[i] != 0 || binary || len == 4 || len == 8) { + + line[j] = 0; + sprintf(tmp, "\\x%02x", (u8)mem[i]); + strcat(line, tmp); + j = strlen(line); + + } + + binary = 1; + + } + + } + + line[j] = 0; + strcat(line, "\"\n"); + if (write(fd, line, strlen(line)) <= 0) + PFATAL("Could not write to dictionary file"); + fsync(fd); + + if (!be_quiet) fprintf(stderr, "Found dictionary token: %s", line); + +} + +bool AFLdict2filePass::runOnModule(Module &M) { + + DenseMap<Value *, std::string *> valueMap; + char * ptr; + int fd, found = 0; + + /* Show a banner */ + setvbuf(stdout, NULL, _IONBF, 0); + + if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { + + SAYF(cCYA "afl-llvm-dict2file" VERSION cRST + " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n"); + + } else + + be_quiet = 1; + + scanForDangerousFunctions(&M); + + ptr = getenv("AFL_LLVM_DICT2FILE"); + + if (!ptr || *ptr != '/') + FATAL("AFL_LLVM_DICT2FILE is not set to an absolute path: %s", ptr); + + if ((fd = open(ptr, O_WRONLY | O_APPEND | O_CREAT | O_DSYNC, 0644)) < 0) + PFATAL("Could not open/create %s.", ptr); + + /* Instrument all the things! */ + + for (auto &F : M) { + + if (isIgnoreFunction(&F)) continue; + + /* Some implementation notes. + * + * We try to handle 3 cases: + * - memcmp("foo", arg, 3) <- literal string + * - static char globalvar[] = "foo"; + * memcmp(globalvar, arg, 3) <- global variable + * - char localvar[] = "foo"; + * memcmp(locallvar, arg, 3) <- local variable + * + * The local variable case is the hardest. We can only detect that + * case if there is no reassignment or change in the variable. + * And it might not work across llvm version. + * What we do is hooking the initializer function for local variables + * (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned + * variable. And if that variable is then used in a compare function + * we use that noted string. + * This seems not to work for tokens that have a size <= 4 :-( + * + * - if the compared length is smaller than the string length we + * save the full string. This is likely better for fuzzing but + * might be wrong in a few cases depending on optimizers + * + * - not using StringRef because there is a bug in the llvm 11 + * checkout I am using which sometimes points to wrong strings + * + * Over and out. Took me a full day. damn. mh/vh + */ + + for (auto &BB : F) { + + for (auto &IN : BB) { + + CallInst *callInst = nullptr; + CmpInst * cmpInst = nullptr; + + if ((cmpInst = dyn_cast<CmpInst>(&IN))) { + + Value * op = cmpInst->getOperand(1); + ConstantInt *ilen = dyn_cast<ConstantInt>(op); + + if (ilen) { + + u64 val2 = 0, val = ilen->getZExtValue(); + u32 len = 0; + if (val > 0x10000 && val < 0xffffffff) len = 4; + if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8; + + if (len) { + + auto c = cmpInst->getPredicate(); + + switch (c) { + + case CmpInst::FCMP_OGT: // fall through + case CmpInst::FCMP_OLE: // fall through + case CmpInst::ICMP_SLE: // fall through + case CmpInst::ICMP_SGT: + + // signed comparison and it is a negative constant + if ((len == 4 && (val & 80000000)) || + (len == 8 && (val & 8000000000000000))) { + + if ((val & 0xffff) != 1) val2 = val - 1; + break; + + } + + // fall through + + case CmpInst::FCMP_UGT: // fall through + case CmpInst::FCMP_ULE: // fall through + case CmpInst::ICMP_UGT: // fall through + case CmpInst::ICMP_ULE: + if ((val & 0xffff) != 0xfffe) val2 = val + 1; + break; + + case CmpInst::FCMP_OLT: // fall through + case CmpInst::FCMP_OGE: // fall through + case CmpInst::ICMP_SLT: // fall through + case CmpInst::ICMP_SGE: + + // signed comparison and it is a negative constant + if ((len == 4 && (val & 80000000)) || + (len == 8 && (val & 8000000000000000))) { + + if ((val & 0xffff) != 1) val2 = val - 1; + break; + + } + + // fall through + + case CmpInst::FCMP_ULT: // fall through + case CmpInst::FCMP_UGE: // fall through + case CmpInst::ICMP_ULT: // fall through + case CmpInst::ICMP_UGE: + if ((val & 0xffff) != 1) val2 = val - 1; + break; + + default: + val2 = 0; + + } + + dict2file(fd, (u8 *)&val, len); + found++; + if (val2) { + + dict2file(fd, (u8 *)&val2, len); + found++; + + } + + } + + } + + } + + if ((callInst = dyn_cast<CallInst>(&IN))) { + + bool isStrcmp = true; + bool isMemcmp = true; + bool isStrncmp = true; + bool isStrcasecmp = true; + bool isStrncasecmp = true; + bool isIntMemcpy = true; + bool addedNull = false; + size_t optLen = 0; + + Function *Callee = callInst->getCalledFunction(); + if (!Callee) continue; + if (callInst->getCallingConv() != llvm::CallingConv::C) continue; + std::string FuncName = Callee->getName().str(); + isStrcmp &= !FuncName.compare("strcmp"); + isMemcmp &= !FuncName.compare("memcmp"); + isStrncmp &= !FuncName.compare("strncmp"); + isStrcasecmp &= !FuncName.compare("strcasecmp"); + isStrncasecmp &= !FuncName.compare("strncasecmp"); + isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64"); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp && !isIntMemcpy) + continue; + + /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function + * prototype */ + FunctionType *FT = Callee->getFunctionType(); + + isStrcmp &= + FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()); + isStrcasecmp &= + FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()); + isMemcmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0)->isPointerTy() && + FT->getParamType(1)->isPointerTy() && + FT->getParamType(2)->isIntegerTy(); + isStrncmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + isStrncasecmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp && !isIntMemcpy) + continue; + + /* is a str{n,}{case,}cmp/memcmp, check if we have + * str{case,}cmp(x, "const") or str{case,}cmp("const", x) + * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..) + * memcmp(x, "const", ..) or memcmp("const", x, ..) */ + Value *Str1P = callInst->getArgOperand(0), + *Str2P = callInst->getArgOperand(1); + std::string Str1, Str2; + StringRef TmpStr; + bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + if (TmpStr.empty()) { + + HasStr1 = false; + + } else { + + HasStr1 = true; + Str1 = TmpStr.str(); + + } + + bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + if (TmpStr.empty()) { + + HasStr2 = false; + + } else { + + HasStr2 = true; + Str2 = TmpStr.str(); + + } + + if (debug) + fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n", + FuncName.c_str(), Str1P, Str1P->getName().str().c_str(), + Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P, + Str2P->getName().str().c_str(), Str2.c_str(), + HasStr2 == true ? "true" : "false"); + + // we handle the 2nd parameter first because of llvm memcpy + if (!HasStr2) { + + auto *Ptr = dyn_cast<ConstantExpr>(Str2P); + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { + + if (Var->hasInitializer()) { + + if (auto *Array = + dyn_cast<ConstantDataArray>(Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString().str(); + + } + + } + + } + + } + + } + + // for the internal memcpy routine we only care for the second + // parameter and are not reporting anything. + if (isIntMemcpy == true) { + + if (HasStr2 == true) { + + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast<ConstantInt>(op2); + if (ilen) { + + uint64_t literalLength = Str2.size(); + uint64_t optLength = ilen->getZExtValue(); + if (literalLength + 1 == optLength) { + + Str2.append("\0", 1); // add null byte + addedNull = true; + + } + + } + + valueMap[Str1P] = new std::string(Str2); + + if (debug) + fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P); + continue; + + } + + continue; + + } + + // Neither a literal nor a global variable? + // maybe it is a local variable that we saved + if (!HasStr2) { + + std::string *strng = valueMap[Str2P]; + if (strng && !strng->empty()) { + + Str2 = *strng; + HasStr2 = true; + if (debug) + fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(), Str2P); + + } + + } + + if (!HasStr1) { + + auto Ptr = dyn_cast<ConstantExpr>(Str1P); + + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { + + if (Var->hasInitializer()) { + + if (auto *Array = + dyn_cast<ConstantDataArray>(Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString().str(); + + } + + } + + } + + } + + } + + // Neither a literal nor a global variable? + // maybe it is a local variable that we saved + if (!HasStr1) { + + std::string *strng = valueMap[Str1P]; + if (strng && !strng->empty()) { + + Str1 = *strng; + HasStr1 = true; + if (debug) + fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(), Str1P); + + } + + } + + /* handle cases of one string is const, one string is variable */ + if (!(HasStr1 ^ HasStr2)) continue; + + std::string thestring; + + if (HasStr1) + thestring = Str1; + else + thestring = Str2; + + optLen = thestring.length(); + + if (isMemcmp || isStrncmp || isStrncasecmp) { + + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast<ConstantInt>(op2); + if (ilen) { + + uint64_t literalLength = optLen; + optLen = ilen->getZExtValue(); + if (literalLength + 1 == optLen) { // add null byte + thestring.append("\0", 1); + addedNull = true; + + } + + } + + } + + // add null byte if this is a string compare function and a null + // was not already added + if (!isMemcmp) { + + if (addedNull == false) { + + thestring.append("\0", 1); // add null byte + optLen++; + + } + + // ensure we do not have garbage + size_t offset = thestring.find('\0', 0); + if (offset + 1 < optLen) optLen = offset + 1; + thestring = thestring.substr(0, optLen); + + } + + // we take the longer string, even if the compare was to a + // shorter part. Note that depending on the optimizer of the + // compiler this can be wrong, but it is more likely that this + // is helping the fuzzer + if (optLen != thestring.length()) optLen = thestring.length(); + if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA; + if (optLen < 3) // too short? skip + continue; + + ptr = (char *)thestring.c_str(); + + dict2file(fd, (u8 *)ptr, optLen); + found++; + + } + + } + + } + + } + + close(fd); + + /* Say something nice. */ + + if (!be_quiet) { + + if (!found) + OKF("No entries for a dictionary found."); + else + OKF("Wrote %d entries to the dictionary file.\n", found); + + } + + return true; + +} + +char AFLdict2filePass::ID = 0; + +static void registerAFLdict2filePass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { + + PM.add(new AFLdict2filePass()); + +} + +static RegisterPass<AFLdict2filePass> X("afl-dict2file", + "afl++ dict2file instrumentation pass", + false, false); + +static RegisterStandardPasses RegisterAFLdict2filePass( + PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass); + +static RegisterStandardPasses RegisterAFLdict2filePass0( + PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass); + diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 125db229..125db229 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc diff --git a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index a7331444..a7331444 100644 --- a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc diff --git a/llvm_mode/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 8c8c987a..8c8c987a 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc diff --git a/llvm_mode/afl-llvm-rt-lto.o.c b/instrumentation/afl-llvm-rt-lto.o.c index e53785ff..e53785ff 100644 --- a/llvm_mode/afl-llvm-rt-lto.o.c +++ b/instrumentation/afl-llvm-rt-lto.o.c diff --git a/llvm_mode/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index d5de3dbb..d5de3dbb 100644 --- a/llvm_mode/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc diff --git a/llvm_mode/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc index c44f38c4..c44f38c4 100644 --- a/llvm_mode/cmplog-routines-pass.cc +++ b/instrumentation/cmplog-routines-pass.cc diff --git a/llvm_mode/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index acdd0f3b..acdd0f3b 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc diff --git a/llvm_mode/llvm-ngram-coverage.h b/instrumentation/llvm-ngram-coverage.h index 12b666e9..12b666e9 100644 --- a/llvm_mode/llvm-ngram-coverage.h +++ b/instrumentation/llvm-ngram-coverage.h diff --git a/llvm_mode/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 2fb90e5e..2fb90e5e 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc diff --git a/llvm_mode/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index a79d4114..a79d4114 100644 --- a/llvm_mode/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile deleted file mode 100644 index 3666a74d..00000000 --- a/llvm_mode/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - @gmake all || echo please install GNUmake diff --git a/llvm_mode/README.instrim.md b/llvm_mode/README.instrim.md deleted file mode 100644 index 7758091b..00000000 --- a/llvm_mode/README.instrim.md +++ /dev/null @@ -1,25 +0,0 @@ -# InsTrim - -InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing - -## Introduction - -InsTrim uses CFG and markers to instrument just what is necessary in the -binary in llvm_mode. It is about 10-15% faster without disadvantages. -It requires at least llvm version 3.8.0. - -## Usage - -Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1` -during compilation of the target. - -There is also an advanced mode which instruments loops in a way so that -afl-fuzz can see which loop path has been selected but not being able to -see how often the loop has been rerun. -This again is a tradeoff for speed for less path information. -To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`. - -## Background - -The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing] -(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c deleted file mode 100644 index ccdbca9d..00000000 --- a/llvm_mode/afl-clang-fast.c +++ /dev/null @@ -1,1143 +0,0 @@ -/* - american fuzzy lop++ - LLVM-mode wrapper for clang - ------------------------------------------------ - - Written by Laszlo Szekeres <lszekeres@google.com> and - Michal Zalewski - - LLVM integration design comes from Laszlo Szekeres. - - Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This program is a drop-in replacement for clang, similar in most respects - to ../afl-gcc. It tries to figure out compilation mode, adds a bunch - of flags, and then calls the real compiler. - - */ - -#define AFL_MAIN - -#include "common.h" -#include "config.h" -#include "types.h" -#include "debug.h" -#include "alloc-inl.h" -#include "llvm-ngram-coverage.h" - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <limits.h> -#include <assert.h> - -#include "llvm/Config/llvm-config.h" - -static u8 * obj_path; /* Path to runtime libraries */ -static u8 **cc_params; /* Parameters passed to the real CC */ -static u32 cc_par_cnt = 1; /* Param count, including argv0 */ -static u8 llvm_fullpath[PATH_MAX]; -static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode, cpp_mode; -static u8 *lto_flag = AFL_CLANG_FLTO; -static u8 debug; -static u8 cwd[4096]; -static u8 cmplog_mode; -u8 use_stdin = 0; /* dummy */ -// static u8 *march_opt = CFLAGS_OPT; - -enum { - - INSTURMENT_DEFAULT = 0, - INSTRUMENT_CLASSIC = 1, - INSTRUMENT_AFL = 1, - INSTRUMENT_PCGUARD = 2, - INSTRUMENT_INSTRIM = 3, - INSTRUMENT_CFG = 3, - INSTRUMENT_LTO = 4, - INSTRUMENT_OPT_CTX = 8, - INSTRUMENT_OPT_NGRAM = 16 - -}; - -char instrument_mode_string[18][18] = { - - "DEFAULT", "CLASSIC", "PCGUARD", "CFG", "LTO", "", "", "", "CTX", "", - "", "", "", "", "", "", "NGRAM", "" - -}; - -u8 *getthecwd() { - - static u8 fail[] = ""; - if (getcwd(cwd, sizeof(cwd)) == NULL) return fail; - return cwd; - -} - -/* Try to find the runtime libraries. If that fails, abort. */ - -static void find_obj(u8 *argv0) { - - u8 *afl_path = getenv("AFL_PATH"); - u8 *slash, *tmp; - - if (afl_path) { - -#ifdef __ANDROID__ - tmp = alloc_printf("%s/afl-llvm-rt.so", afl_path); -#else - tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); -#endif - - if (!access(tmp, R_OK)) { - - obj_path = afl_path; - ck_free(tmp); - return; - - } - - ck_free(tmp); - - } - - slash = strrchr(argv0, '/'); - - if (slash) { - - u8 *dir; - - *slash = 0; - dir = ck_strdup(argv0); - *slash = '/'; - -#ifdef __ANDROID__ - tmp = alloc_printf("%s/afl-llvm-rt.so", dir); -#else - tmp = alloc_printf("%s/afl-llvm-rt.o", dir); -#endif - - if (!access(tmp, R_OK)) { - - obj_path = dir; - ck_free(tmp); - return; - - } - - ck_free(tmp); - ck_free(dir); - - } - -#ifdef __ANDROID__ - if (!access(AFL_PATH "/afl-llvm-rt.so", R_OK)) { - -#else - if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { - -#endif - - obj_path = AFL_PATH; - return; - - } - - FATAL( - "Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set " - "AFL_PATH"); - -} - -/* Copy argv to cc_params, making the necessary edits. */ - -static void edit_params(u32 argc, char **argv, char **envp) { - - u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0, - preprocessor_only = 0; - u8 have_pic = 0; - u8 *name; - - cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); - - name = strrchr(argv[0], '/'); - if (!name) - name = argv[0]; - else - ++name; - - if (lto_mode) - if (lto_flag[0] != '-') - FATAL( - "Using afl-clang-lto is not possible because Makefile magic did not " - "identify the correct -flto flag"); - - if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++") || - !strcmp(name, "afl-clang++")) { - - u8 *alt_cxx = getenv("AFL_CXX"); - if (USE_BINDIR) - snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", LLVM_BINDIR); - else - sprintf(llvm_fullpath, CLANGPP_BIN); - cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; - cpp_mode = 1; - - } else if (!strcmp(name, "afl-clang-fast") || - - !strcmp(name, "afl-clang-lto") || !strcmp(name, "afl-clang")) { - - u8 *alt_cc = getenv("AFL_CC"); - if (USE_BINDIR) - snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR); - else - sprintf(llvm_fullpath, CLANG_BIN); - cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath; - - } else { - - fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL( - "Name of the binary is not a known name, expected afl-clang-fast(++) " - "or afl-clang-lto(++)"); - - } - - cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument"; - - if (lto_mode && cpp_mode) - cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early - - /* There are several ways to compile with afl-clang-fast. In the traditional - mode, we use afl-llvm-pass.so, then there is libLLVMInsTrim.so which is - faster and creates less map pollution. - Then there is the 'trace-pc-guard' mode, we use native LLVM - instrumentation callbacks instead. For trace-pc-guard see: - http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards - The best instrumentatation is with the LTO modes, the classic and - InsTrimLTO, the latter is faster. The LTO modes are activated by using - afl-clang-lto(++) - */ - - if (lto_mode) { - - if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || - getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || - getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { - - 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-lto-instrumentlist.so", obj_path); - - } - - } - - // laf - if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) { - - if (lto_mode) { - - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); - - } 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/split-switches-pass.so", obj_path); - - } - - } - - if (getenv("LAF_TRANSFORM_COMPARES") || - getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { - - if (lto_mode) { - - cc_params[cc_par_cnt++] = alloc_printf( - "-Wl,-mllvm=-load=%s/compare-transform-pass.so", obj_path); - - } 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/compare-transform-pass.so", obj_path); - - } - - } - - if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") || - getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) { - - if (lto_mode) { - - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/split-compares-pass.so", obj_path); - - } 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/split-compares-pass.so", obj_path); - - } - - } - - // /laf - - unsetenv("AFL_LD"); - unsetenv("AFL_LD_CALLER"); - if (cmplog_mode) { - - if (lto_mode) { - - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path); - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); - cc_params[cc_par_cnt++] = alloc_printf( - "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path); - - } 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/cmplog-routines-pass.so", obj_path); - - // reuse split switches from laf - 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); - - 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/cmplog-instructions-pass.so", obj_path); - - } - - cc_params[cc_par_cnt++] = "-fno-inline"; - - } - - if (lto_mode) { - -#if defined(AFL_CLANG_LDPATH) && LLVM_VERSION_MAJOR >= 12 - u8 *ld_ptr = strrchr(AFL_REAL_LD, '/'); - if (!ld_ptr) ld_ptr = "ld.lld"; - cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_ptr); - cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", AFL_REAL_LD); -#else - cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD); -#endif - - cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; - - if (instrument_mode == INSTRUMENT_CFG) - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path); - else - - cc_params[cc_par_cnt++] = alloc_printf( - "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path); - cc_params[cc_par_cnt++] = lto_flag; - - } else { - - if (instrument_mode == INSTRUMENT_PCGUARD) { - -#if LLVM_VERSION_MAJOR > 4 || \ - (LLVM_VERSION_MAJOR == 4 && \ - (LLVM_VERSION_MINOR > 0 || LLVM_VERSION_PATCH >= 1)) - cc_params[cc_par_cnt++] = - "-fsanitize-coverage=trace-pc-guard"; // edge coverage by default -#else - FATAL("pcguard instrumentation requires llvm 4.0.1+"); -#endif - - } else { - - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - if (instrument_mode == INSTRUMENT_CFG) - 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); - - } - - } - - // cc_params[cc_par_cnt++] = "-Qunused-arguments"; - - // in case LLVM is installed not via a package manager or "make install" - // e.g. compiled download or compiled from github then it's ./lib directory - // might not be in the search path. Add it if so. - u8 *libdir = strdup(LLVM_LIBDIR); - if (cpp_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) && - strncmp(libdir, "/lib", 4)) { - - cc_params[cc_par_cnt++] = "-rpath"; - cc_params[cc_par_cnt++] = libdir; - - } else { - - free(libdir); - - } - - u32 idx; - if (lto_mode && argc > 1) { - - for (idx = 1; idx < argc; idx++) { - - if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1; - - } - - if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC"; - - } - - /* Detect stray -v calls from ./configure scripts. */ - - while (--argc) { - - u8 *cur = *(++argv); - - if (!strcmp(cur, "-m32")) bit_mode = 32; - if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; - if (!strcmp(cur, "-m64")) bit_mode = 64; - - if (!strcmp(cur, "-x")) x_set = 1; - - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) - asan_set = 1; - - if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; - - if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined")) - continue; - - if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; - if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; - - if (!strcmp(cur, "-E")) preprocessor_only = 1; - if (!strcmp(cur, "-shared")) shared_linking = 1; - - cc_params[cc_par_cnt++] = cur; - - } - - if (getenv("AFL_HARDEN")) { - - cc_params[cc_par_cnt++] = "-fstack-protector-all"; - - if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; - - } - - if (!asan_set) { - - if (getenv("AFL_USE_ASAN")) { - - if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive"); - - if (getenv("AFL_HARDEN")) - FATAL("ASAN and AFL_HARDEN are mutually exclusive"); - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=address"; - - } else if (getenv("AFL_USE_MSAN")) { - - if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive"); - - if (getenv("AFL_HARDEN")) - FATAL("MSAN and AFL_HARDEN are mutually exclusive"); - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=memory"; - - } - - } - - if (getenv("AFL_USE_UBSAN")) { - - cc_params[cc_par_cnt++] = "-fsanitize=undefined"; - cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error"; - cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all"; - - } - - if (getenv("AFL_USE_CFISAN")) { - - if (!lto_mode) { - - uint32_t i = 0, found = 0; - while (envp[i] != NULL && !found) - if (strncmp("-flto", envp[i++], 5) == 0) found = 1; - if (!found) cc_params[cc_par_cnt++] = "-flto"; - - } - - cc_params[cc_par_cnt++] = "-fsanitize=cfi"; - cc_params[cc_par_cnt++] = "-fvisibility=hidden"; - - } - - if (!getenv("AFL_DONT_OPTIMIZE")) { - - cc_params[cc_par_cnt++] = "-g"; - cc_params[cc_par_cnt++] = "-O3"; - cc_params[cc_par_cnt++] = "-funroll-loops"; - // if (strlen(march_opt) > 1 && march_opt[0] == '-') - // cc_params[cc_par_cnt++] = march_opt; - - } - - if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") || - getenv("LAF_TRANSFORM_COMPARES") || lto_mode) { - - cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; - - } - -#if defined(USEMMAP) && !defined(__HAIKU__) - 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"; - - /* When the user tries to use persistent or deferred forkserver modes by - appending a single line to the program, we want to reliably inject a - signature into the binary (to be picked up by afl-fuzz) and we want - to call a function from the runtime .o file. This is unnecessarily - painful for three reasons: - - 1) We need to convince the compiler not to optimize out the signature. - This is done with __attribute__((used)). - - 2) We need to convince the linker, when called with -Wl,--gc-sections, - not to do the same. This is done by forcing an assignment to a - 'volatile' pointer. - - 3) We need to declare __afl_persistent_loop() in the global namespace, - but doing this within a method in a class is hard - :: and extern "C" - are forbidden and __attribute__((alias(...))) doesn't work. Hence the - __asm__ aliasing trick. - - */ - - cc_params[cc_par_cnt++] = - "-D__AFL_FUZZ_INIT()=" - "int __afl_sharedmem_fuzzing = 1;" - "extern unsigned int *__afl_fuzz_len;" - "extern unsigned char *__afl_fuzz_ptr;" - "unsigned char __afl_fuzz_alt[1024000];" - "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;"; - cc_params[cc_par_cnt++] = - "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : " - "__afl_fuzz_alt_ptr)"; - cc_params[cc_par_cnt++] = - "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : " - "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1024000)) == 0xffffffff " - "? 0 : *__afl_fuzz_len)"; - - cc_params[cc_par_cnt++] = - "-D__AFL_LOOP(_A)=" - "({ static volatile char *_B __attribute__((used)); " - " _B = (char*)\"" PERSIST_SIG - "\"; " -#ifdef __APPLE__ - "__attribute__((visibility(\"default\"))) " - "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " -#else - "__attribute__((visibility(\"default\"))) " - "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " -#endif /* ^__APPLE__ */ - "_L(_A); })"; - - cc_params[cc_par_cnt++] = - "-D__AFL_INIT()=" - "do { static volatile char *_A __attribute__((used)); " - " _A = (char*)\"" DEFER_SIG - "\"; " -#ifdef __APPLE__ - "__attribute__((visibility(\"default\"))) " - "void _I(void) __asm__(\"___afl_manual_init\"); " -#else - "__attribute__((visibility(\"default\"))) " - "void _I(void) __asm__(\"__afl_manual_init\"); " -#endif /* ^__APPLE__ */ - "_I(); } while (0)"; - - if (x_set) { - - cc_params[cc_par_cnt++] = "-x"; - cc_params[cc_par_cnt++] = "none"; - - } - - if (preprocessor_only) { - - /* In the preprocessor_only case (-E), we are not actually compiling at - all but requesting the compiler to output preprocessed sources only. - We must not add the runtime in this case because the compiler will - simply output its binary content back on stdout, breaking any build - systems that rely on a separate source preprocessing step. */ - cc_params[cc_par_cnt] = NULL; - return; - - } - -#ifndef __ANDROID__ - switch (bit_mode) { - - case 0: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); - if (lto_mode) - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt-lto.o", obj_path); - break; - - case 32: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); - if (access(cc_params[cc_par_cnt - 1], R_OK)) - FATAL("-m32 is not supported by your compiler"); - if (lto_mode) { - - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path); - if (access(cc_params[cc_par_cnt - 1], R_OK)) - FATAL("-m32 is not supported by your compiler"); - - } - - break; - - case 64: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); - if (access(cc_params[cc_par_cnt - 1], R_OK)) - FATAL("-m64 is not supported by your compiler"); - if (lto_mode) { - - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path); - if (access(cc_params[cc_par_cnt - 1], R_OK)) - FATAL("-m64 is not supported by your compiler"); - - } - - break; - - } - - #ifndef __APPLE__ - if (!shared_linking) - cc_params[cc_par_cnt++] = - alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); - #endif - -#endif - - cc_params[cc_par_cnt] = NULL; - -} - -/* Main entry point */ - -int main(int argc, char **argv, char **envp) { - - int i; - char *callname = "afl-clang-fast", *ptr = NULL; - - if (getenv("AFL_DEBUG")) { - - debug = 1; - if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG"); - - } else if (getenv("AFL_QUIET")) - - be_quiet = 1; - - if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") || - getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) { - - if (instrument_mode == 0) - instrument_mode = INSTRUMENT_PCGUARD; - else if (instrument_mode != INSTRUMENT_PCGUARD) - FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together"); - - } - - if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || - getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || - getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) && - getenv("AFL_DONT_OPTIMIZE")) - WARNF( - "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined " - "for file matching, only function matching!"); - - if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || - getenv("INSTRIM_LIB")) { - - if (instrument_mode == 0) - instrument_mode = INSTRUMENT_CFG; - else if (instrument_mode != INSTRUMENT_CFG) - FATAL( - "you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together"); - - } - - if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX; - - if (getenv("AFL_LLVM_NGRAM_SIZE")) { - - instrument_opt_mode |= INSTRUMENT_OPT_NGRAM; - ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE")); - if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) - FATAL( - "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX " - "(%u)", - NGRAM_SIZE_MAX); - - } - - if (getenv("AFL_LLVM_INSTRUMENT")) { - - u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); - - while (ptr) { - - if (strncasecmp(ptr, "afl", strlen("afl")) == 0 || - strncasecmp(ptr, "classic", strlen("classic")) == 0) { - - if (instrument_mode == INSTRUMENT_LTO) { - - instrument_mode = INSTRUMENT_CLASSIC; - lto_mode = 1; - - } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) - - instrument_mode = INSTRUMENT_AFL; - else - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); - - } - - if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || - strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) { - - if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) - instrument_mode = INSTRUMENT_PCGUARD; - else - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); - - } - - if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || - strncasecmp(ptr, "instrim", strlen("instrim")) == 0) { - - if (instrument_mode == INSTRUMENT_LTO) { - - instrument_mode = INSTRUMENT_CFG; - lto_mode = 1; - - } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG) - - instrument_mode = INSTRUMENT_CFG; - else - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); - - } - - if (strncasecmp(ptr, "lto", strlen("lto")) == 0) { - - lto_mode = 1; - if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) - instrument_mode = INSTRUMENT_LTO; - else if (instrument_mode != INSTRUMENT_CFG) - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); - - } - - if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { - - instrument_opt_mode |= INSTRUMENT_OPT_CTX; - setenv("AFL_LLVM_CTX", "1", 1); - - } - - if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { - - ptr += strlen("ngram"); - while (*ptr && (*ptr < '0' || *ptr > '9')) { - - ptr++; - - } - - if (!*ptr) { - - ptr = getenv("AFL_LLVM_NGRAM_SIZE"); - if (!ptr || !*ptr) { - - FATAL( - "you must set the NGRAM size with (e.g. for value 2) " - "AFL_LLVM_INSTRUMENT=ngram-2"); - - } - - } - - ngram_size = atoi(ptr); - if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) - FATAL( - "NGRAM instrumentation option must be between 2 and " - "NGRAM_SIZE_MAX " - "(%u)", - NGRAM_SIZE_MAX); - instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); - ptr = alloc_printf("%u", ngram_size); - setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); - - } - - ptr = strtok(NULL, ":,;"); - - } - - } - - if (strstr(argv[0], "afl-clang-lto") != NULL) { - - if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO || - instrument_mode == INSTRUMENT_CFG) { - - lto_mode = 1; - callname = "afl-clang-lto"; - if (!instrument_mode) { - - instrument_mode = INSTRUMENT_CFG; - ptr = instrument_mode_string[instrument_mode]; - - } - - } else if (instrument_mode == INSTRUMENT_LTO || - - instrument_mode == INSTRUMENT_CLASSIC) { - - lto_mode = 1; - callname = "afl-clang-lto"; - - } else { - - if (!be_quiet) - WARNF("afl-clang-lto called with mode %s, using that mode instead", - instrument_mode_string[instrument_mode]); - - } - - } - - if (instrument_mode == 0) { - -#if LLVM_VERSION_MAJOR <= 6 - instrument_mode = INSTRUMENT_AFL; -#else - if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || - getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || - getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { - - instrument_mode = INSTRUMENT_AFL; - WARNF( - "switching to classic instrumentation because " - "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use " - "-fsanitize-coverage-allowlist=allowlist.txt or " - "-fsanitize-coverage-blocklist=denylist.txt if you want to use " - "PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ " - "SanitizerCoverage.html#partially-disabling-instrumentation"); - - } else - - instrument_mode = INSTRUMENT_PCGUARD; -#endif - - } - - if (instrument_opt_mode && lto_mode) - FATAL( - "CTX and NGRAM can not be used in LTO mode (and would make LTO " - "useless)"); - - if (!instrument_opt_mode) { - - if (lto_mode && instrument_mode == INSTRUMENT_CFG) - ptr = alloc_printf("InsTrimLTO"); - else - ptr = instrument_mode_string[instrument_mode]; - - } else if (instrument_opt_mode == INSTRUMENT_OPT_CTX) - - ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]); - else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM) - ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode], - ngram_size); - else - ptr = alloc_printf("%s + CTX + NGRAM-%u", - instrument_mode_string[instrument_mode], ngram_size); - -#ifndef AFL_CLANG_FLTO - if (lto_mode) - FATAL( - "instrumentation mode LTO specified but LLVM support not available " - "(requires LLVM 11 or higher)"); -#endif - - if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && - instrument_mode != INSTRUMENT_CFG) - FATAL( - "CTX and NGRAM instrumentation options can only be used with CFG " - "(recommended) and CLASSIC instrumentation modes!"); - - if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO")) - FATAL( - "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set " - "together"); - - if (instrument_mode == INSTRUMENT_PCGUARD && - (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || - getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || - getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST"))) - FATAL( - "Instrumentation type PCGUARD does not support " - "AFL_LLVM_ALLOWLIST/DENYLIST! Use " - "-fsanitize-coverage-allowlist=allowlist.txt or " - "-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm " - "12+), see " - "https://clang.llvm.org/docs/" - "SanitizerCoverage.html#partially-disabling-instrumentation"); - - if (argc < 2 || strcmp(argv[1], "-h") == 0) { - - if (!lto_mode) - printf("afl-clang-fast" VERSION " by <lszekeres@google.com> in %s mode\n", - ptr); - else - printf("afl-clang-lto" VERSION - " by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in %s mode\n", - ptr); - - SAYF( - "\n" - "%s[++] [options]\n" - "\n" - "This is a helper application for afl-fuzz. It serves as a drop-in " - "replacement\n" - "for clang, letting you recompile third-party code with the " - "required " - "runtime\n" - "instrumentation. A common use pattern would be one of the " - "following:\n\n" - - " CC=%s/afl-clang-fast ./configure\n" - " CXX=%s/afl-clang-fast++ ./configure\n\n" - - "In contrast to the traditional afl-clang tool, this version is " - "implemented as\n" - "an LLVM pass and tends to offer improved performance with slow " - "programs.\n\n" - - "Environment variables used:\n" - "AFL_CC: path to the C compiler to use\n" - "AFL_CXX: path to the C++ compiler to use\n" - "AFL_DEBUG: enable developer debugging output\n" - "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" - "AFL_HARDEN: adds code hardening to catch memory bugs\n" - "AFL_INST_RATIO: percentage of branches to instrument\n" -#if LLVM_VERSION_MAJOR < 9 - "AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n" -#else - "AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n" -#endif - "AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n" - "AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n" - "AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n" - " to cascaded comparisons\n" - "AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to " - "cascaded comp.\n" - "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison " - "function calls\n" - "AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n" - "AFL_LLVM_INSTRUMENT_ALLOW/AFL_LLVM_INSTRUMENT_DENY: enable instrument" - "allow/deny listing (selective instrumentation)\n" - "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" - "AFL_PATH: path to instrumenting pass and runtime " - "(afl-llvm-rt.*o)\n" - "AFL_LLVM_DOCUMENT_IDS: document edge IDs given to which function (LTO " - "only)\n" - "AFL_QUIET: suppress verbose output\n" - "AFL_USE_ASAN: activate address sanitizer\n" - "AFL_USE_CFISAN: activate control flow sanitizer\n" - "AFL_USE_MSAN: activate memory sanitizer\n" - "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n", - callname, BIN_PATH, BIN_PATH); - - SAYF( - "\nafl-clang-fast specific environment variables:\n" - "AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n" - "AFL_LLVM_INSTRUMENT: set instrumentation mode: AFL, CFG " - "(INSTRIM), PCGUARD [DEFAULT], LTO, CTX, NGRAM-2 ... NGRAM-16\n" - " You can also use the old environment variables instead:\n" - " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation " - "[DEFAULT]\n" - " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" - " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (" - "option to INSTRIM)\n" - " AFL_LLVM_CTX: use context sensitive coverage\n" - " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n"); - -#ifdef AFL_CLANG_FLTO - SAYF( - "\nafl-clang-lto specific environment variables:\n" - "AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), e.g. " - "0x10000\n" - "AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " - "functions they are in into this file\n" - "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " - "global var\n" - "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a " - "bb\n" - "AFL_REAL_LD: use this lld linker instead of the compiled in path\n" - "\nafl-clang-lto was built with linker target \"%s\" and LTO flags " - "\"%s\"\n" - "If anything fails - be sure to read README.lto.md!\n", - AFL_REAL_LD, AFL_CLANG_FLTO); -#endif - - SAYF( - "\nafl-clang-fast was built for llvm %s with the llvm binary path " - "of \"%s\".\n", - LLVM_VERSION, LLVM_BINDIR); - - SAYF("\n"); - - exit(1); - - } else if ((isatty(2) && !be_quiet) || - - getenv("AFL_DEBUG") != NULL) { - - if (!lto_mode) - - SAYF(cCYA "afl-clang-fast" VERSION cRST - " by <lszekeres@google.com> in %s mode\n", - ptr); - - else - - SAYF(cCYA "afl-clang-lto" VERSION cRST - " by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in mode %s\n", - ptr); - - } - - u8 *ptr2; - if (!be_quiet && !lto_mode && - ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) { - - u32 map_size = atoi(ptr2); - if (map_size != MAP_SIZE) - WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast"); - - } - - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < argc; i++) - SAYF(" \"%s\"", argv[i]); - SAYF("\n"); - - } - - check_environment_vars(envp); - - if (getenv("AFL_LLVM_LAF_ALL")) { - - setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1); - setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1); - setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1); - setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1); - - } - - cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG"); - if (!be_quiet && cmplog_mode) - printf("CmpLog mode by <andreafioraldi@gmail.com>\n"); - -#ifndef __ANDROID__ - find_obj(argv[0]); -#endif - - edit_params(argc, argv, envp); - - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < cc_par_cnt; i++) - SAYF(" \"%s\"", cc_params[i]); - SAYF("\n"); - - } - - execvp(cc_params[0], (char **)cc_params); - - FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); - - return 0; - -} - diff --git a/src/afl-cc.c b/src/afl-cc.c new file mode 100644 index 00000000..e11ce40a --- /dev/null +++ b/src/afl-cc.c @@ -0,0 +1,1544 @@ +/* + american fuzzy lop++ - compiler instrumentation wrapper + ------------------------------------------------------- + + Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse + + Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#define AFL_MAIN + +#include "common.h" +#include "config.h" +#include "types.h" +#include "debug.h" +#include "alloc-inl.h" +#include "llvm-ngram-coverage.h" + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <limits.h> +#include <assert.h> + +#if (LLVM_MAJOR - 0 == 0) + #undef LLVM_MAJOR +#endif +#if !defined(LLVM_MAJOR) + #define LLVM_MAJOR 0 +#endif + +static u8 * obj_path; /* Path to runtime libraries */ +static u8 **cc_params; /* Parameters passed to the real CC */ +static u32 cc_par_cnt = 1; /* Param count, including argv0 */ +static u8 llvm_fullpath[PATH_MAX]; +static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode, + compiler_mode, plusplus_mode; +static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto; +static u8 *lto_flag = AFL_CLANG_FLTO, *argvnull; +static u8 debug; +static u8 cwd[4096]; +static u8 cmplog_mode; +u8 use_stdin; /* dummy */ +// static u8 *march_opt = CFLAGS_OPT; + +enum { + + INSTURMENT_DEFAULT = 0, + INSTRUMENT_CLASSIC = 1, + INSTRUMENT_AFL = 1, + INSTRUMENT_PCGUARD = 2, + INSTRUMENT_INSTRIM = 3, + INSTRUMENT_CFG = 3, + INSTRUMENT_LTO = 4, + INSTRUMENT_OPT_CTX = 8, + INSTRUMENT_OPT_NGRAM = 16 + +}; + +char instrument_mode_string[18][18] = { + + "DEFAULT", "CLASSIC", "PCGUARD", "CFG", "LTO", "", "", "", "CTX", "", + "", "", "", "", "", "", "NGRAM", "" + +}; + +enum { + + UNSET = 0, + LTO = 1, + LLVM = 2, + GCC_PLUGIN = 3, + GCC = 4 + +}; + +char compiler_mode_string[6][12] = { + + "AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN", + "GCC", "" + +}; + +u8 *getthecwd() { + + static u8 fail[] = ""; + if (getcwd(cwd, sizeof(cwd)) == NULL) return fail; + return cwd; + +} + +/* Try to find the runtime libraries. If that fails, abort. */ + +static u8 *find_object(u8 *obj, u8 *argv0) { + + u8 *afl_path = getenv("AFL_PATH"); + u8 *slash = NULL, *tmp; + + if (afl_path) { + +#ifdef __ANDROID__ + tmp = alloc_printf("%s/%s", afl_path, obj); +#else + tmp = alloc_printf("%s/%s", afl_path, obj); +#endif + + if (!access(tmp, R_OK)) { + + obj_path = afl_path; + return tmp; + + } + + ck_free(tmp); + + } + + if (argv0) slash = strrchr(argv0, '/'); + + if (slash) { + + u8 *dir; + + *slash = 0; + dir = ck_strdup(argv0); + *slash = '/'; + +#ifdef __ANDROID__ + tmp = alloc_printf("%s/%s", dir, obj); +#else + tmp = alloc_printf("%s/%s", dir, obj); +#endif + + if (!access(tmp, R_OK)) { + + obj_path = dir; + return tmp; + + } + + ck_free(tmp); + ck_free(dir); + + } + + tmp = alloc_printf("%s/%s", AFL_PATH, obj); +#ifdef __ANDROID__ + if (!access(tmp, R_OK)) { + +#else + if (!access(tmp, R_OK)) { + +#endif + + obj_path = AFL_PATH; + return tmp; + + } + + ck_free(tmp); + return NULL; + +} + +/* Try to find the runtime libraries. If that fails, abort. */ + +static void find_obj(u8 *argv0) { + + u8 *afl_path = getenv("AFL_PATH"); + u8 *slash, *tmp; + + if (afl_path) { + +#ifdef __ANDROID__ + tmp = alloc_printf("%s/afl-compiler-rt.so", afl_path); +#else + tmp = alloc_printf("%s/afl-compiler-rt.o", afl_path); +#endif + + if (!access(tmp, R_OK)) { + + obj_path = afl_path; + ck_free(tmp); + return; + + } + + ck_free(tmp); + + } + + slash = strrchr(argv0, '/'); + + if (slash) { + + u8 *dir; + + *slash = 0; + dir = ck_strdup(argv0); + *slash = '/'; + +#ifdef __ANDROID__ + tmp = alloc_printf("%s/afl-compiler-rt.so", dir); +#else + tmp = alloc_printf("%s/afl-compiler-rt.o", dir); +#endif + + if (!access(tmp, R_OK)) { + + obj_path = dir; + ck_free(tmp); + return; + + } + + ck_free(tmp); + ck_free(dir); + + } + +#ifdef __ANDROID__ + if (!access(AFL_PATH "/afl-compiler-rt.so", R_OK)) { + +#else + if (!access(AFL_PATH "/afl-compiler-rt.o", R_OK)) { + +#endif + + obj_path = AFL_PATH; + return; + + } + + FATAL( + "Unable to find 'afl-compiler-rt.o' or 'afl-llvm-pass.so'. Please set " + "AFL_PATH"); + +} + +/* Copy argv to cc_params, making the necessary edits. */ + +static void edit_params(u32 argc, char **argv, char **envp) { + + u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0, + preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0; + u8 *name; + + cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); + + name = strrchr(argv[0], '/'); + if (!name) + name = argv[0]; + else + ++name; + + if (lto_mode) { + + if (lto_flag[0] != '-') + FATAL( + "Using afl-clang-lto is not possible because Makefile magic did not " + "identify the correct -flto flag"); + else + compiler_mode = LTO; + + } + + if (plusplus_mode) { + + u8 *alt_cxx = getenv("AFL_CXX"); + + if (!alt_cxx) { + + if (compiler_mode >= GCC_PLUGIN) { + + alt_cxx = "g++"; + + } else { + + if (USE_BINDIR) + snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", + LLVM_BINDIR); + else + snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN); + alt_cxx = llvm_fullpath; + + } + + } + + cc_params[0] = alt_cxx; + + } else { + + u8 *alt_cc = getenv("AFL_CC"); + + if (!alt_cc) { + + if (compiler_mode >= GCC_PLUGIN) { + + alt_cc = "gcc"; + + } else { + + if (USE_BINDIR) + snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", + LLVM_BINDIR); + else + snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN); + alt_cc = llvm_fullpath; + + } + + } + + cc_params[0] = alt_cc; + + } + + if (compiler_mode == GCC) { + + cc_params[cc_par_cnt++] = "-B"; + cc_params[cc_par_cnt++] = obj_path; + + } + + if (compiler_mode == GCC_PLUGIN) { + + char *fplugin_arg = + alloc_printf("-fplugin=%s", find_object("afl-gcc-pass.so", argvnull)); + cc_params[cc_par_cnt++] = fplugin_arg; + + } + + if (compiler_mode == LLVM || compiler_mode == LTO) { + + cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument"; + + if (lto_mode && plusplus_mode) + cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early + + if (lto_mode) { + + if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { + + 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-lto-instrumentlist.so", obj_path); + + } + + } + + if (getenv("AFL_LLVM_DICT2FILE")) { + + 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-dict2file.so", obj_path); + + } + + // laf + if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) { + + if (lto_mode) { + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); + + } 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/split-switches-pass.so", obj_path); + + } + + } + + if (getenv("LAF_TRANSFORM_COMPARES") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { + + if (lto_mode) { + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/compare-transform-pass.so", obj_path); + + } 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/compare-transform-pass.so", obj_path); + + } + + } + + if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") || + getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) { + + if (lto_mode) { + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/split-compares-pass.so", obj_path); + + } 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/split-compares-pass.so", obj_path); + + } + + } + + // /laf + + unsetenv("AFL_LD"); + unsetenv("AFL_LD_CALLER"); + if (cmplog_mode) { + + if (lto_mode) { + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path); + + } 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/cmplog-routines-pass.so", obj_path); + + // reuse split switches from laf + 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); + + 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/cmplog-instructions-pass.so", obj_path); + + } + + cc_params[cc_par_cnt++] = "-fno-inline"; + + } + + if (lto_mode) { + + u8 *ld_path = strdup(AFL_REAL_LD); + if (!*ld_path) ld_path = "ld.lld"; +#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12 + cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path); +#else + cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path); +#endif + + cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; + + if (instrument_mode == INSTRUMENT_CFG) + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path); + else + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path); + cc_params[cc_par_cnt++] = lto_flag; + + } else { + + if (instrument_mode == INSTRUMENT_PCGUARD) { + +#if LLVM_MAJOR >= 4 + cc_params[cc_par_cnt++] = + "-fsanitize-coverage=trace-pc-guard"; // edge coverage by default +#else + FATAL("pcguard instrumentation requires llvm 4.0.1+"); +#endif + + } else { + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + if (instrument_mode == INSTRUMENT_CFG) + 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); + + } + + } + + // cc_params[cc_par_cnt++] = "-Qunused-arguments"; + + // in case LLVM is installed not via a package manager or "make install" + // e.g. compiled download or compiled from github then its ./lib directory + // might not be in the search path. Add it if so. + u8 *libdir = strdup(LLVM_LIBDIR); + if (plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) && + strncmp(libdir, "/lib", 4)) { + + cc_params[cc_par_cnt++] = "-rpath"; + cc_params[cc_par_cnt++] = libdir; + + } else { + + free(libdir); + + } + + u32 idx; + if (lto_mode && argc > 1) { + + for (idx = 1; idx < argc; idx++) { + + if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1; + + } + + if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC"; + + } + + } + + /* Detect stray -v calls from ./configure scripts. */ + + while (--argc) { + + u8 *cur = *(++argv); + + if (!strncmp(cur, "--afl", 5)) continue; + if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; + if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; + if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined")) + continue; + + if (!strcmp(cur, "-m32")) bit_mode = 32; + if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; + if (!strcmp(cur, "-m64")) bit_mode = 64; + + if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) + asan_set = 1; + + if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; + + if (!strcmp(cur, "-x")) x_set = 1; + if (!strcmp(cur, "-E")) preprocessor_only = 1; + if (!strcmp(cur, "-shared")) shared_linking = 1; + + if (!strncmp(cur, "-O", 2)) have_o = 1; + if (!strncmp(cur, "-f", 2) && strstr(cur, "unroll-loop")) have_unroll = 1; + + cc_params[cc_par_cnt++] = cur; + + } + + if (getenv("AFL_HARDEN")) { + + cc_params[cc_par_cnt++] = "-fstack-protector-all"; + + if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; + + } + + if (!asan_set) { + + if (getenv("AFL_USE_ASAN")) { + + if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive"); + + if (getenv("AFL_HARDEN")) + FATAL("ASAN and AFL_HARDEN are mutually exclusive"); + + cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; + cc_params[cc_par_cnt++] = "-fsanitize=address"; + + } else if (getenv("AFL_USE_MSAN")) { + + if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive"); + + if (getenv("AFL_HARDEN")) + FATAL("MSAN and AFL_HARDEN are mutually exclusive"); + + cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; + cc_params[cc_par_cnt++] = "-fsanitize=memory"; + + } + + } + + if (getenv("AFL_USE_UBSAN")) { + + cc_params[cc_par_cnt++] = "-fsanitize=undefined"; + cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error"; + cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all"; + + } + + if (getenv("AFL_USE_CFISAN")) { + + if (!lto_mode) { + + uint32_t i = 0, found = 0; + while (envp[i] != NULL && !found) + if (strncmp("-flto", envp[i++], 5) == 0) found = 1; + if (!found) cc_params[cc_par_cnt++] = "-flto"; + + } + + cc_params[cc_par_cnt++] = "-fsanitize=cfi"; + cc_params[cc_par_cnt++] = "-fvisibility=hidden"; + + } + + if (!getenv("AFL_DONT_OPTIMIZE")) { + + cc_params[cc_par_cnt++] = "-g"; + if (!have_o) cc_params[cc_par_cnt++] = "-O3"; + if (!have_unroll) cc_params[cc_par_cnt++] = "-funroll-loops"; + // if (strlen(march_opt) > 1 && march_opt[0] == '-') + // cc_params[cc_par_cnt++] = march_opt; + + } + + if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") || + getenv("LAF_TRANSFORM_COMPARES") || lto_mode) { + + cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; + cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; + + } + +#if defined(USEMMAP) && !defined(__HAIKU__) + 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"; + + /* When the user tries to use persistent or deferred forkserver modes by + appending a single line to the program, we want to reliably inject a + signature into the binary (to be picked up by afl-fuzz) and we want + to call a function from the runtime .o file. This is unnecessarily + painful for three reasons: + + 1) We need to convince the compiler not to optimize out the signature. + This is done with __attribute__((used)). + + 2) We need to convince the linker, when called with -Wl,--gc-sections, + not to do the same. This is done by forcing an assignment to a + 'volatile' pointer. + + 3) We need to declare __afl_persistent_loop() in the global namespace, + but doing this within a method in a class is hard - :: and extern "C" + are forbidden and __attribute__((alias(...))) doesn't work. Hence the + __asm__ aliasing trick. + + */ + + cc_params[cc_par_cnt++] = + "-D__AFL_FUZZ_INIT()=" + "int __afl_sharedmem_fuzzing = 1;" + "extern unsigned int *__afl_fuzz_len;" + "extern unsigned char *__afl_fuzz_ptr;" + "unsigned char __afl_fuzz_alt[1024000];" + "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;"; + cc_params[cc_par_cnt++] = + "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : " + "__afl_fuzz_alt_ptr)"; + cc_params[cc_par_cnt++] = + "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : " + "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1024000)) == 0xffffffff " + "? 0 : *__afl_fuzz_len)"; + + cc_params[cc_par_cnt++] = + "-D__AFL_LOOP(_A)=" + "({ static volatile char *_B __attribute__((used)); " + " _B = (char*)\"" PERSIST_SIG + "\"; " +#ifdef __APPLE__ + "__attribute__((visibility(\"default\"))) " + "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " +#else + "__attribute__((visibility(\"default\"))) " + "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " +#endif /* ^__APPLE__ */ + "_L(_A); })"; + + cc_params[cc_par_cnt++] = + "-D__AFL_INIT()=" + "do { static volatile char *_A __attribute__((used)); " + " _A = (char*)\"" DEFER_SIG + "\"; " +#ifdef __APPLE__ + "__attribute__((visibility(\"default\"))) " + "void _I(void) __asm__(\"___afl_manual_init\"); " +#else + "__attribute__((visibility(\"default\"))) " + "void _I(void) __asm__(\"__afl_manual_init\"); " +#endif /* ^__APPLE__ */ + "_I(); } while (0)"; + + if (x_set) { + + cc_params[cc_par_cnt++] = "-x"; + cc_params[cc_par_cnt++] = "none"; + + } + + if (preprocessor_only) { + + /* In the preprocessor_only case (-E), we are not actually compiling at + all but requesting the compiler to output preprocessed sources only. + We must not add the runtime in this case because the compiler will + simply output its binary content back on stdout, breaking any build + systems that rely on a separate source preprocessing step. */ + cc_params[cc_par_cnt] = NULL; + return; + + } + +#ifndef __ANDROID__ + + if (compiler_mode != GCC) { + + switch (bit_mode) { + + case 0: + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-compiler-rt.o", obj_path); + if (lto_mode) + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto.o", obj_path); + break; + + case 32: + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-compiler-rt-32.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m32 is not supported by your compiler"); + if (lto_mode) { + + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m32 is not supported by your compiler"); + + } + + break; + + case 64: + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-compiler-rt-64.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m64 is not supported by your compiler"); + if (lto_mode) { + + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m64 is not supported by your compiler"); + + } + + break; + + } + + #ifndef __APPLE__ + if (!shared_linking) + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); + #endif + + } + +#endif + + cc_params[cc_par_cnt] = NULL; + +} + +/* Main entry point */ + +int main(int argc, char **argv, char **envp) { + + int i; + char *callname = argv[0], *ptr = NULL; + + if (getenv("AFL_DEBUG")) { + + debug = 1; + if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG"); + + } else if (getenv("AFL_QUIET")) + + be_quiet = 1; + + if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1; + argvnull = (u8 *)argv[0]; + check_environment_vars(envp); + + if ((ptr = find_object("as", argv[0])) != NULL) { + + have_gcc = 1; + ck_free(ptr); + + } + +#if (LLVM_MAJOR > 2) + + if ((ptr = find_object("SanitizerCoverageLTO.so", argv[0])) != NULL) { + + have_lto = 1; + ck_free(ptr); + + } + + if ((ptr = find_object("cmplog-routines-pass.so", argv[0])) != NULL) { + + have_llvm = 1; + ck_free(ptr); + + } + +#endif + + if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) { + + have_gcc_plugin = 1; + ck_free(ptr); + + } + +#if (LLVM_MAJOR > 2) + + if (strncmp(callname, "afl-clang-fast", 14) == 0) { + + compiler_mode = LLVM; + + } else if (strncmp(callname, "afl-clang-lto", 13) == 0 || + + strncmp(callname, "afl-lto", 7) == 0) { + + compiler_mode = LTO; + + } else + +#endif + if (strncmp(callname, "afl-gcc-fast", 12) == 0 || + + strncmp(callname, "afl-g++-fast", 12) == 0) { + + compiler_mode = GCC_PLUGIN; + + } else if (strncmp(callname, "afl-gcc", 7) == 0 || + + strncmp(callname, "afl-g++", 7) == 0) { + + compiler_mode = GCC; + + } + + if ((ptr = getenv("AFL_CC_COMPILER"))) { + + if (compiler_mode) { + + WARNF( + "\"AFL_CC_COMPILER\" is set but a specific compiler was already " + "selected by command line parameter or symlink, ignoring the " + "environment variable!"); + + } else { + + if (strncasecmp(ptr, "LTO", 3) == 0) { + + compiler_mode = LTO; + + } else if (strncasecmp(ptr, "LLVM", 4) == 0) { + + compiler_mode = LLVM; + + } else if (strncasecmp(ptr, "GCC_P", 5) == 0 || + + strncasecmp(ptr, "GCC-P", 5) == 0 || + strncasecmp(ptr, "GCCP", 4) == 0) { + + compiler_mode = GCC_PLUGIN; + + } else if (strcasecmp(ptr, "GCC") == 0) { + + compiler_mode = GCC; + + } else + + FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr); + + } + + } + + for (i = 1; i < argc; i++) { + + if (strncmp(argv[i], "--afl", 5) == 0) { + + if (compiler_mode) + WARNF( + "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " + "symlink compiler selection!"); + + ptr = argv[i]; + ptr += 5; + while (*ptr == '-') + ptr++; + + if (strncasecmp(ptr, "LTO", 3) == 0) { + + compiler_mode = LTO; + + } else if (strncasecmp(ptr, "LLVM", 4) == 0) { + + compiler_mode = LLVM; + + } else if (strncasecmp(ptr, "GCC_P", 5) == 0 || + + strncasecmp(ptr, "GCC-P", 5) == 0 || + strncasecmp(ptr, "GCCP", 4) == 0) { + + compiler_mode = GCC_PLUGIN; + + } else if (strcasecmp(ptr, "GCC") == 0) { + + compiler_mode = GCC; + + } else + + FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]); + + } + + } + + if (strlen(callname) > 2 && + (strncmp(callname + strlen(callname) - 2, "++", 2) == 0 || + strstr(callname, "-g++") != NULL)) + plusplus_mode = 1; + + if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") || + getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) { + + if (instrument_mode == 0) + instrument_mode = INSTRUMENT_PCGUARD; + else if (instrument_mode != INSTRUMENT_PCGUARD) + FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together"); + + } + + if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) && + getenv("AFL_DONT_OPTIMIZE")) + WARNF( + "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined " + "for file matching, only function matching!"); + + if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || + getenv("INSTRIM_LIB")) { + + if (instrument_mode == 0) + instrument_mode = INSTRUMENT_CFG; + else if (instrument_mode != INSTRUMENT_CFG) + FATAL( + "you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together"); + + } + + if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX; + + if (getenv("AFL_LLVM_NGRAM_SIZE")) { + + instrument_opt_mode |= INSTRUMENT_OPT_NGRAM; + ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE")); + if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) + FATAL( + "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX " + "(%u)", + NGRAM_SIZE_MAX); + + } + + if (getenv("AFL_LLVM_INSTRUMENT")) { + + u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); + + while (ptr) { + + if (strncasecmp(ptr, "afl", strlen("afl")) == 0 || + strncasecmp(ptr, "classic", strlen("classic")) == 0) { + + if (instrument_mode == INSTRUMENT_LTO) { + + instrument_mode = INSTRUMENT_CLASSIC; + lto_mode = 1; + + } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) + + instrument_mode = INSTRUMENT_AFL; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || + strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) + instrument_mode = INSTRUMENT_PCGUARD; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || + strncasecmp(ptr, "instrim", strlen("instrim")) == 0) { + + if (instrument_mode == INSTRUMENT_LTO) { + + instrument_mode = INSTRUMENT_CFG; + lto_mode = 1; + + } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG) + + instrument_mode = INSTRUMENT_CFG; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "lto", strlen("lto")) == 0) { + + lto_mode = 1; + if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) + instrument_mode = INSTRUMENT_LTO; + else if (instrument_mode != INSTRUMENT_CFG) + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { + + instrument_opt_mode |= INSTRUMENT_OPT_CTX; + setenv("AFL_LLVM_CTX", "1", 1); + + } + + if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { + + ptr += strlen("ngram"); + while (*ptr && (*ptr < '0' || *ptr > '9')) + ptr++; + + if (!*ptr) { + + if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL) + FATAL( + "you must set the NGRAM size with (e.g. for value 2) " + "AFL_LLVM_INSTRUMENT=ngram-2"); + + } + + ngram_size = atoi(ptr); + if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) + FATAL( + "NGRAM instrumentation option must be between 2 and " + "NGRAM_SIZE_MAX " + "(%u)", + NGRAM_SIZE_MAX); + instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); + ptr = alloc_printf("%u", ngram_size); + setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); + + } + + ptr = strtok(NULL, ":,;"); + + } + + } + + if (!compiler_mode) { + + // lto is not a default because outside of afl-cc RANLIB and AR have to + // be set to llvm versions so this would work + if (have_llvm) + compiler_mode = LLVM; + else if (have_gcc_plugin) + compiler_mode = GCC_PLUGIN; + else if (have_gcc) + compiler_mode = GCC; + else if (have_lto) + compiler_mode = LTO; + else + FATAL("no compiler mode available"); + + } + + if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { + + char *fp; + fp = realpath(argv[0], NULL); + + printf("afl-cc" VERSION + " by Michal Zalewski, Laszlo Szekeres, Marc Heuse\n"); + + SAYF( + "\n" + "afl-cc/afl-c++ [options]\n" + "\n" + "This is a helper application for afl-fuzz. It serves as a drop-in " + "replacement\n" + "for gcc and clang, letting you recompile third-party code with the " + "required\n" + "runtime instrumentation. A common use pattern would be one of the " + "following:\n\n" + + " CC=afl-cc CXX=afl-c++ ./configure --disable-shared\n" + " cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ .\n" + " CC=afl-cc CXX=afl-c++ meson\n\n"); + + SAYF( + " |---------------- FEATURES " + "---------------|\n" + "MODES: NCC PERSIST SNAP DICT LAF " + "CMPLOG SELECT\n" + " [LTO] llvm LTO: %s%s\n" + " PCGUARD DEFAULT yes yes yes yes yes yes " + " yes\n" + " CLASSIC yes yes yes yes yes yes " + " yes\n" + " [LLVM] llvm: %s%s\n" + " PCGUARD %s yes yes yes module yes yes " + "extern\n" + " CLASSIC %s no yes yes module yes yes " + "yes\n" + " - NORMAL\n" + " - CTX\n" + " - NGRAM-{2-16}\n" + " INSTRIM no yes yes module yes yes " + " yes\n" + " - NORMAL\n" + " - CTX\n" + " - NGRAM-{2-16}\n" + " [GCC_PLUGIN] gcc plugin: %s%s\n" + " CLASSIC DEFAULT no yes yes no no no " + " simple\n" + " [GCC] simple gcc: %s%s\n" + " CLASSIC DEFAULT no no no no no no " + " no\n\n", + have_lto ? "AVAILABLE" : "unavailable!", + compiler_mode == LTO ? " [SELECTED]" : "", + have_llvm ? "AVAILABLE" : "unavailable!", + compiler_mode == LLVM ? " [SELECTED]" : "", + LLVM_MAJOR > 6 ? "DEFAULT" : " ", + LLVM_MAJOR > 6 ? " " : "DEFAULT", + have_gcc_plugin ? "AVAILABLE" : "unavailable!", + compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "", + have_gcc ? "AVAILABLE" : "unavailable!", + compiler_mode == GCC ? " [SELECTED]" : ""); + + SAYF( + "Modes:\n" + " To select the compiler mode use a symlink version (e.g. " + "afl-clang-fast), set\n" + " the environment variable AFL_CC_COMPILER to a mode (e.g. LLVM) or " + "use the\n" + " command line parameter --afl-MODE (e.g. --afl-llvm). If none is " + "selected,\n" + " afl-cc will select the best available (LLVM -> GCC_PLUGIN -> GCC).\n" + " The best is LTO but it often needs RANLIB and AR settings outside " + "of afl-cc.\n\n"); + + SAYF( + "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best " + "available)\n" + " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n" + " CLASSIC: decision target instrumentation (README.llvm.md)\n" + " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" + " NGRAM-x: CLASSIC + previous path " + "((instrumentation/README.ngram.md)\n" + " INSTRIM: Dominator tree (for LLVM <= 6.0) " + "(instrumentation/README.instrim.md)\n\n"); + + SAYF( + "Features: (see documentation links)\n" + " NCC: non-colliding coverage [automatic] (that is an amazing " + "thing!)\n" + " (instrumentation/README.lto.md)\n" + " PERSIST: persistent mode support [code] (huge speed increase!)\n" + " (instrumentation/README.persistent_mode.md)\n" + " SNAP: linux lkm snapshot module support [automatic] (speed " + "increase)\n" + " (https://github.com/AFLplusplus/AFL-Snapshot-LKM/)\n" + " DICT: dictionary in the target [yes=automatic or llvm module " + "pass]\n" + " (instrumentation/README.lto.md + " + "instrumentation/README.llvm.md)\n" + " LAF: comparison splitting [env] " + "(instrumentation/README.laf-intel.md)\n" + " CMPLOG: input2state exploration [env] " + "(instrumentation/README.cmplog.md)\n" + " SELECT: selective instrumentation (allow/deny) on filename or " + "function [env]\n" + " (instrumentation/README.instrument_list.md)\n\n"); + + if (argc < 2 || strncmp(argv[1], "-hh", 3)) { + + SAYF( + "To see all environment variables for the configuration of afl-cc " + "use \"-hh\".\n"); + + } else { + + SAYF( + "Environment variables used:\n" + " AFL_CC: path to the C compiler to use\n" + " AFL_CXX: path to the C++ compiler to use\n" + " AFL_DEBUG: enable developer debugging output\n" + " AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" + " AFL_HARDEN: adds code hardening to catch memory bugs\n" + " AFL_INST_RATIO: percentage of branches to instrument\n" +#if LLVM_MAJOR < 9 + " AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n" +#else + " AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n" +#endif + " AFL_LLVM_DICT2FILE: generate an afl dictionary based on found " + "comparisons\n" + " AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n" + " AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n" + " AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n" + " AFL_LLVM_LAF_SPLIT_SWITCHES: cascaded comparisons on switches\n" + " AFL_LLVM_LAF_SPLIT_FLOATS: cascaded comparisons on floats\n" + " AFL_LLVM_LAF_TRANSFORM_COMPARES: cascade comparisons for string " + "functions\n" + " AFL_LLVM_INSTRUMENT_ALLOW/AFL_LLVM_INSTRUMENT_DENY: enable " + "instrument allow/\n" + " deny listing (selective instrumentation)\n" + " AFL_NO_BUILTIN: no builtins for string compare functions (for " + "libtokencap.so)\n" + " AFL_PATH: path to instrumenting pass and runtime " + "(afl-compiler-rt.*o)\n" + " AFL_LLVM_DOCUMENT_IDS: document edge IDs given to which function " + "(LTO only)\n" + " AFL_QUIET: suppress verbose output\n" + " AFL_USE_ASAN: activate address sanitizer\n" + " AFL_USE_CFISAN: activate control flow sanitizer\n" + " AFL_USE_MSAN: activate memory sanitizer\n" + " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n", + BIN_PATH, BIN_PATH); + + SAYF( + "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " + "variables:\n" + " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n" + " AFL_LLVM_INSTRUMENT: set instrumentation mode: CLASSIC, INSTRIM, " + "PCGUARD, LTO, CTX, NGRAM-2 ... NGRAM-16\n" + " You can also use the old environment variables instead:\n" + " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" + " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" + " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed " + "(option to INSTRIM)\n" + " AFL_LLVM_CTX: use context sensitive coverage (for CLASSIC and " + "INSTRIM)\n" + " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for " + "CLASSIC and INSTRIM)\n"); + +#ifdef AFL_CLANG_FLTO + SAYF( + "\nLTO/afl-clang-lto specific environment variables:\n" + "AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), e.g. " + "0x10000\n" + "AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " + "functions they are in into this file\n" + "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " + "global var\n" + "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a " + "bb\n" + "AFL_REAL_LD: use this lld linker instead of the compiled in path\n" + "\nafl-clang-lto was built with linker target \"%s\" and LTO flags " + "\"%s\"\n" + "If anything fails - be sure to read README.lto.md!\n", + AFL_REAL_LD, AFL_CLANG_FLTO); +#endif + + } + + SAYF( + "For any information on the available instrumentations and options " + "please \n" + "consult the README.md, especially section 3.1 about instrumenting " + "targets.\n\n"); + +#if (LLVM_MAJOR > 2) + if (have_lto) + SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO); + if (have_llvm) + SAYF("afl-cc LLVM version %d with the the binary path \"%s\".\n", + LLVM_MAJOR, LLVM_BINDIR); + if (have_lto || have_llvm) SAYF("\n"); +#endif + + SAYF( + "Do not be overwhelmed :) afl-cc uses good defaults if no options are " + "selected.\n" + "Read the documentation for FEATURES though, all are good but few are " + "defaults.\n\n"); + + exit(1); + + } + + if (compiler_mode == LTO) { + + if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO || + instrument_mode == INSTRUMENT_CFG) { + + lto_mode = 1; + if (!instrument_mode) { + + instrument_mode = INSTRUMENT_CFG; + ptr = instrument_mode_string[instrument_mode]; + + } + + } else if (instrument_mode == INSTRUMENT_LTO || + + instrument_mode == INSTRUMENT_CLASSIC) { + + lto_mode = 1; + + } else { + + if (!be_quiet) + WARNF("afl-clang-lto called with mode %s, using that mode instead", + instrument_mode_string[instrument_mode]); + + } + + } + + if (instrument_mode == 0 && compiler_mode < GCC_PLUGIN) { + +#if LLVM_MAJOR <= 6 + instrument_mode = INSTRUMENT_AFL; +#else + if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { + + instrument_mode = INSTRUMENT_AFL; + WARNF( + "switching to classic instrumentation because " + "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use " + "-fsanitize-coverage-allowlist=allowlist.txt or " + "-fsanitize-coverage-blocklist=denylist.txt if you want to use " + "PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ " + "SanitizerCoverage.html#partially-disabling-instrumentation"); + + } else + + instrument_mode = INSTRUMENT_PCGUARD; +#endif + + } + + if (instrument_opt_mode && compiler_mode != LLVM) + FATAL("CTX and NGRAM can only be used in LLVM mode"); + + if (!instrument_opt_mode) { + + if (lto_mode && instrument_mode == INSTRUMENT_CFG) + instrument_mode = INSTRUMENT_PCGUARD; + ptr = instrument_mode_string[instrument_mode]; + + } else { + + if (instrument_opt_mode == INSTRUMENT_OPT_CTX) + + ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]); + else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM) + ptr = alloc_printf("%s + NGRAM-%u", + instrument_mode_string[instrument_mode], ngram_size); + else + ptr = alloc_printf("%s + CTX + NGRAM-%u", + instrument_mode_string[instrument_mode], ngram_size); + + } + +#ifndef AFL_CLANG_FLTO + if (lto_mode) + FATAL( + "instrumentation mode LTO specified but LLVM support not available " + "(requires LLVM 11 or higher)"); +#endif + + if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && + instrument_mode != INSTRUMENT_CFG) + FATAL( + "CTX and NGRAM instrumentation options can only be used with CFG " + "(recommended) and CLASSIC instrumentation modes!"); + + if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO")) + FATAL( + "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set " + "together"); + + if (instrument_mode == INSTRUMENT_PCGUARD && + (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST"))) + FATAL( + "Instrumentation type PCGUARD does not support " + "AFL_LLVM_ALLOWLIST/DENYLIST! Use " + "-fsanitize-coverage-allowlist=allowlist.txt or " + "-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm " + "12+), see " + "https://clang.llvm.org/docs/" + "SanitizerCoverage.html#partially-disabling-instrumentation"); + + u8 *ptr2; + + if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/') + FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path"); + + if ((isatty(2) && !be_quiet) || debug) { + + SAYF(cCYA + "afl-cc " VERSION cRST + " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n", + compiler_mode_string[compiler_mode], ptr); + + } + + if (!be_quiet && !lto_mode && + ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) { + + u32 map_size = atoi(ptr2); + if (map_size != MAP_SIZE) + WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast"); + + } + + if (debug) { + + SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); + for (i = 0; i < argc; i++) + SAYF(" \"%s\"", argv[i]); + SAYF("\n"); + + } + + if (getenv("AFL_LLVM_LAF_ALL")) { + + setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1); + setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1); + setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1); + setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1); + + } + + cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG"); + if (!be_quiet && cmplog_mode) + printf("CmpLog mode by <andreafioraldi@gmail.com>\n"); + +#ifndef __ANDROID__ + find_obj(argv[0]); +#endif + + edit_params(argc, argv, envp); + + if (debug) { + + SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); + for (i = 0; i < cc_par_cnt; i++) + SAYF(" \"%s\"", cc_params[i]); + SAYF("\n"); + + } + + execvp(cc_params[0], (char **)cc_params); + + FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); + + return 0; + +} + diff --git a/src/afl-gcc.c b/src/afl-gcc.c deleted file mode 100644 index 97564aea..00000000 --- a/src/afl-gcc.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - american fuzzy lop++ - wrapper for GCC and clang - ------------------------------------------------ - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and - Andrea Fioraldi <andreafioraldi@gmail.com> - - Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This program is a drop-in replacement for GCC or clang. The most common way - of using it is to pass the path to afl-gcc or afl-clang via CC when invoking - ./configure. - - (Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.) - - The wrapper needs to know the path to afl-as (renamed to 'as'). The default - is /usr/local/lib/afl/. A convenient way to specify alternative directories - would be to set AFL_PATH. - - If AFL_HARDEN is set, the wrapper will compile the target app with various - hardening options that may help detect memory management issues more - reliably. You can also specify AFL_USE_ASAN to enable ASAN. - - If you want to call a non-default compiler as a next step of the chain, - specify its location via AFL_CC or AFL_CXX. - - */ - -#define AFL_MAIN - -#include "config.h" -#include "types.h" -#include "debug.h" -#include "alloc-inl.h" - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> - -static u8 * as_path; /* Path to the AFL 'as' wrapper */ -static u8 **cc_params; /* Parameters passed to the real CC */ -static u32 cc_par_cnt = 1; /* Param count, including argv0 */ -static u8 be_quiet, /* Quiet mode */ - clang_mode; /* Invoked as afl-clang*? */ - -/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived - from argv[0]. If that fails, abort. */ - -static void find_as(u8 *argv0) { - - u8 *afl_path = getenv("AFL_PATH"); - u8 *slash, *tmp; - - if (afl_path) { - - tmp = alloc_printf("%s/as", afl_path); - - if (!access(tmp, X_OK)) { - - as_path = afl_path; - ck_free(tmp); - return; - - } - - ck_free(tmp); - - } - - slash = strrchr(argv0, '/'); - - if (slash) { - - u8 *dir; - - *slash = 0; - dir = ck_strdup(argv0); - *slash = '/'; - - tmp = alloc_printf("%s/afl-as", dir); - - if (!access(tmp, X_OK)) { - - as_path = dir; - ck_free(tmp); - return; - - } - - ck_free(tmp); - ck_free(dir); - - } - - if (!access(AFL_PATH "/as", X_OK)) { - - as_path = AFL_PATH; - return; - - } - - FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); - -} - -/* Copy argv to cc_params, making the necessary edits. */ - -static void edit_params(u32 argc, char **argv) { - - u8 fortify_set = 0, asan_set = 0; - u8 *name; - -#if defined(__FreeBSD__) && defined(WORD_SIZE_64) - u8 m32_set = 0; -#endif - - cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); - - name = strrchr(argv[0], '/'); - if (!name) { - - name = argv[0]; - - /* This should never happen but fixes a scan-build warning */ - if (!name) { FATAL("Empty argv set"); } - - } else { - - ++name; - - } - - if (!strncmp(name, "afl-clang", 9)) { - - clang_mode = 1; - - setenv(CLANG_ENV_VAR, "1", 1); - - if (!strcmp(name, "afl-clang++")) { - - u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++"; - - } else if (!strcmp(name, "afl-clang")) { - - u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang"; - - } else { - - fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL("Name of the binary is not a known name, expected afl-clang(++)"); - - } - - } else { - - /* With GCJ and Eclipse installed, you can actually compile Java! The - instrumentation will work (amazingly). Alas, unhandled exceptions do - not call abort(), so afl-fuzz would need to be modified to equate - non-zero exit codes with crash conditions when working with Java - binaries. Meh. */ - -#ifdef __APPLE__ - - if (!strcmp(name, "afl-g++")) { - - cc_params[0] = getenv("AFL_CXX"); - - } else if (!strcmp(name, "afl-gcj")) { - - cc_params[0] = getenv("AFL_GCJ"); - - } else if (!strcmp(name, "afl-gcc")) { - - cc_params[0] = getenv("AFL_CC"); - - } else { - - fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj"); - - } - - if (!cc_params[0]) { - - SAYF("\n" cLRD "[-] " cRST - "On Apple systems, 'gcc' is usually just a wrapper for clang. " - "Please use the\n" - " 'afl-clang' utility instead of 'afl-gcc'. If you really have " - "GCC installed,\n" - " set AFL_CC or AFL_CXX to specify the correct path to that " - "compiler.\n"); - - FATAL("AFL_CC or AFL_CXX required on MacOS X"); - - } - -#else - - if (!strcmp(name, "afl-g++")) { - - u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++"; - - } else if (!strcmp(name, "afl-gcj")) { - - u8 *alt_cc = getenv("AFL_GCJ"); - cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj"; - - } else if (!strcmp(name, "afl-gcc")) { - - u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc"; - - } else { - - fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj"); - - } - -#endif /* __APPLE__ */ - - } - - while (--argc) { - - u8 *cur = *(++argv); - - if (!strncmp(cur, "-B", 2)) { - - if (!be_quiet) { WARNF("-B is already set, overriding"); } - - if (!cur[2] && argc > 1) { - - argc--; - argv++; - - } - - continue; - - } - - if (!strcmp(cur, "-integrated-as")) { continue; } - - if (!strcmp(cur, "-pipe")) { continue; } - -#if defined(__FreeBSD__) && defined(WORD_SIZE_64) - if (!strcmp(cur, "-m32")) m32_set = 1; -#endif - - if (!strcmp(cur, "-fsanitize=address") || - !strcmp(cur, "-fsanitize=memory")) { - - asan_set = 1; - - } - - if (strstr(cur, "FORTIFY_SOURCE")) { fortify_set = 1; } - - cc_params[cc_par_cnt++] = cur; - - } - - cc_params[cc_par_cnt++] = "-B"; - cc_params[cc_par_cnt++] = as_path; - - if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; } - - if (getenv("AFL_HARDEN")) { - - cc_params[cc_par_cnt++] = "-fstack-protector-all"; - - if (!fortify_set) { cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; } - - } - - if (asan_set) { - - /* Pass this on to afl-as to adjust map density. */ - - setenv("AFL_USE_ASAN", "1", 1); - - } else if (getenv("AFL_USE_ASAN")) { - - if (getenv("AFL_USE_MSAN")) { - - FATAL("ASAN and MSAN are mutually exclusive"); - - } - - if (getenv("AFL_HARDEN")) { - - FATAL("ASAN and AFL_HARDEN are mutually exclusive"); - - } - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=address"; - - } else if (getenv("AFL_USE_MSAN")) { - - if (getenv("AFL_USE_ASAN")) { - - FATAL("ASAN and MSAN are mutually exclusive"); - - } - - if (getenv("AFL_HARDEN")) { - - FATAL("MSAN and AFL_HARDEN are mutually exclusive"); - - } - - cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; - cc_params[cc_par_cnt++] = "-fsanitize=memory"; - - } - - if (getenv("AFL_USE_UBSAN")) { - - cc_params[cc_par_cnt++] = "-fsanitize=undefined"; - cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error"; - cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all"; - - } - -#if defined(USEMMAP) && !defined(__HAIKU__) - cc_params[cc_par_cnt++] = "-lrt"; -#endif - - if (!getenv("AFL_DONT_OPTIMIZE")) { - -#if defined(__FreeBSD__) && defined(WORD_SIZE_64) - - /* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself - works OK. This has nothing to do with us, but let's avoid triggering - that bug. */ - - if (!clang_mode || !m32_set) cc_params[cc_par_cnt++] = "-g"; - -#else - - cc_params[cc_par_cnt++] = "-g"; - -#endif - - cc_params[cc_par_cnt++] = "-O3"; - cc_params[cc_par_cnt++] = "-funroll-loops"; - - /* Two indicators that you're building for fuzzing; one of them is - AFL-specific, the other is shared with libfuzzer. */ - - cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; - cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; - - } - - if (getenv("AFL_NO_BUILTIN")) { - - cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; - cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; - cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; - - } - - cc_params[cc_par_cnt] = NULL; - -} - -/* Main entry point */ - -int main(int argc, char **argv) { - - char *env_info = - "Environment variables used by afl-gcc:\n" - "AFL_CC: path to the C compiler to use\n" - "AFL_CXX: path to the C++ compiler to use\n" - "AFL_GCJ: path to the java compiler to use\n" - "AFL_PATH: path to the instrumenting assembler\n" - "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" - "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" - "AFL_QUIET: suppress verbose output\n" - "AFL_CAL_FAST: speed up the initial calibration\n" - "AFL_HARDEN: adds code hardening to catch memory bugs\n" - "AFL_USE_ASAN: activate address sanitizer\n" - "AFL_USE_MSAN: activate memory sanitizer\n" - "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" - - "\nEnvironment variables used by afl-as (called by afl-gcc):\n" - "AFL_AS: path to the assembler to use\n" - "TMPDIR: set the directory for temporary files of afl-as\n" - "TEMP: fall back path to directory for temporary files\n" - "TMP: fall back path to directory for temporary files\n" - "AFL_INST_RATIO: percentage of branches to instrument\n" - "AFL_QUIET: suppress verbose output\n" - "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n" - "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n"; - - if (argc == 2 && strncmp(argv[1], "-h", 2) == 0) { - - printf("afl-cc" VERSION " by Michal Zalewski\n\n"); - printf("%s \n\n", argv[0]); - printf("afl-gcc has no command line options\n\n%s\n", env_info); - printf( - "NOTE: afl-gcc is deprecated, llvm_mode is much faster and has more " - "options\n"); - return -1; - - } - - if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { - - SAYF(cCYA "afl-cc" VERSION cRST " by Michal Zalewski\n"); - SAYF(cYEL "[!] " cBRI "NOTE: " cRST - "afl-gcc is deprecated, llvm_mode is much faster and has more " - "options\n"); - - } else { - - be_quiet = 1; - - } - - if (argc < 2) { - - SAYF( - "\n" - "This is a helper application for afl-fuzz. It serves as a drop-in " - "replacement\n" - "for gcc or clang, letting you recompile third-party code with the " - "required\n" - "runtime instrumentation. A common use pattern would be one of the " - "following:\n\n" - - " CC=%s/afl-gcc ./configure\n" - " CXX=%s/afl-g++ ./configure\n\n%s" - - , - BIN_PATH, BIN_PATH, env_info); - - exit(1); - - } - - u8 *ptr; - if (!be_quiet && - ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) { - - u32 map_size = atoi(ptr); - if (map_size != MAP_SIZE) { - - WARNF("AFL_MAP_SIZE is not supported by afl-gcc"); - - } - - } - - find_as(argv[0]); - - edit_params(argc, argv); - - execvp(cc_params[0], (char **)cc_params); - - FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); - - return 0; - -} - diff --git a/llvm_mode/afl-ld-lto.c b/src/afl-ld-lto.c index 771e2d0d..771e2d0d 100644 --- a/llvm_mode/afl-ld-lto.c +++ b/src/afl-ld-lto.c |