first batch of changes

This commit is contained in:
vanhauser-thc
2020-09-05 12:11:48 +02:00
parent fac108476c
commit 996986bed5
43 changed files with 2441 additions and 2833 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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.

View File

@ -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

View File

@ -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!

View 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)

View File

@ -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.

View File

@ -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 :-)

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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). */

View 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);

View File

@ -1,2 +0,0 @@
all:
@gmake all || echo please install GNUmake

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;
}