mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-13 02:28:09 +00:00
first batch of changes
This commit is contained in:
@ -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
|
@ -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: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) 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
|
||||
|
||||
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
|
@ -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
|
@ -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.
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
@ -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.
|
@ -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
|
@ -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!
|
30
instrumentation/README.instrim.md
Normal file
30
instrumentation/README.instrim.md
Normal file
@ -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)
|
@ -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.
|
@ -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 :-)
|
@ -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.
|
@ -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.
|
||||
|
@ -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
|
@ -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.
|
@ -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.
|
@ -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). */
|
599
instrumentation/afl-llvm-dict2file.so.cc
Normal file
599
instrumentation/afl-llvm-dict2file.so.cc
Normal file
@ -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);
|
||||
|
@ -1,2 +0,0 @@
|
||||
all:
|
||||
@gmake all || echo please install GNUmake
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
1544
src/afl-cc.c
Normal file
1544
src/afl-cc.c
Normal file
File diff suppressed because it is too large
Load Diff
488
src/afl-gcc.c
488
src/afl-gcc.c
@ -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;
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user