mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-19 13:03:44 +00:00
6
.gitignore
vendored
6
.gitignore
vendored
@ -51,6 +51,12 @@ afl-showmap.8
|
||||
afl-system-config.8
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
afl-c++
|
||||
afl-cc
|
||||
afl-lto
|
||||
afl-lto++
|
||||
afl-lto++.8
|
||||
afl-lto.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
|
@ -101,7 +101,7 @@ cc_binary_host {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"llvm_mode/afl-clang-fast.c",
|
||||
"src/afl-cc.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ cc_binary_host {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"llvm_mode/afl-clang-fast.c",
|
||||
"src/afl-cc.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -136,6 +136,6 @@ cc_library_static {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"llvm_mode/afl-llvm-rt.o.c",
|
||||
"instrumentation/afl-llvm-rt.o.c",
|
||||
],
|
||||
}
|
||||
|
233
GNUmakefile
233
GNUmakefile
@ -24,30 +24,31 @@ BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
|
||||
PROGS = afl-gcc afl-g++ afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||
@ -61,10 +62,7 @@ ifneq "$(shell uname)" "Darwin"
|
||||
endif
|
||||
endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
# _FORTIFY_SOURCE=2 does not like -O0
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "SunOS"
|
||||
@ -206,10 +204,7 @@ else
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
# _FORTIFY_SOURCE=2 does not like -O0
|
||||
ifndef DEBUG
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
LDFLAGS += -ldl -lrt
|
||||
endif
|
||||
|
||||
@ -223,11 +218,7 @@ ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
TEST_CC = afl-gcc
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
@ -277,28 +268,47 @@ ifdef TEST_MMAP
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
.PHONY: all
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done
|
||||
|
||||
man: afl-gcc all $(MANPAGES)
|
||||
.PHONY: llvm
|
||||
llvm:
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
gcc_plugin:
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
|
||||
.PHONY: man
|
||||
man: $(MANPAGES)
|
||||
|
||||
.PHONY: test
|
||||
test: tests
|
||||
|
||||
.PHONY: tests
|
||||
tests: source-only
|
||||
@cd test ; ./test-all.sh
|
||||
@rm -f test/errors
|
||||
|
||||
.PHONY: performance-tests
|
||||
performance-tests: performance-test
|
||||
.PHONY: test-performance
|
||||
test-performance: performance-test
|
||||
|
||||
.PHONY: performance-test
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
# hint: make targets are also listed in the top level README.md
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap"
|
||||
@echo "source-only: everything for source code fuzzing: gcc_plugin, libdislocator, libtokencap"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@ -322,8 +332,8 @@ help:
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
.PHONY: test_x86
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@ -332,148 +342,129 @@ test_x86:
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
.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_python
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: ready
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-g++: afl-gcc
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
@ln -sf afl-as as
|
||||
|
||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
$(CC) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-common.c -o src/afl-common.o
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
|
||||
.PHONY: document
|
||||
document: afl-fuzz-document
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
|
||||
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
|
||||
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
|
||||
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_maybe_alloc
|
||||
|
||||
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
|
||||
|
||||
unit_hash: test/unittests/unit_hash.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_hash
|
||||
|
||||
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
|
||||
|
||||
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_rand
|
||||
|
||||
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
|
||||
unit_list: test/unittests/unit_list.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_list
|
||||
|
||||
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
|
||||
unit_preallocable: test/unittests/unit_preallocable.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_preallocable
|
||||
|
||||
.PHONY: unit_clean
|
||||
unit_clean:
|
||||
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
|
||||
|
||||
.PHONY: unit
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
|
||||
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
|
||||
else
|
||||
|
||||
unit:
|
||||
@echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: code-format
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i libdislocator/*.c
|
||||
./.custom-format.py -i libtokencap/*.c
|
||||
./.custom-format.py -i llvm_mode/*.c
|
||||
./.custom-format.py -i llvm_mode/*.h
|
||||
./.custom-format.py -i llvm_mode/*.cc
|
||||
./.custom-format.py -i gcc_plugin/*.c
|
||||
@#./.custom-format.py -i gcc_plugin/*.h
|
||||
./.custom-format.py -i gcc_plugin/*.cc
|
||||
./.custom-format.py -i instrumentation/*.h
|
||||
./.custom-format.py -i instrumentation/*.cc
|
||||
./.custom-format.py -i instrumentation/*.c
|
||||
./.custom-format.py -i custom_mutators/*/*.c
|
||||
@#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-(
|
||||
./.custom-format.py -i examples/*/*.c
|
||||
@ -489,38 +480,40 @@ code-format:
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
|
||||
.PHONY: test_build
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
test_build: afl-cc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_AS_FORCE_INSTRUMENT=1 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
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
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
test_build: afl-cc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: all_done
|
||||
all_done: test_build
|
||||
@if [ ! "`type clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.md for a faster alternative to afl-gcc."; fi
|
||||
@test -e afl-cc && echo "[+] Main compiler 'afl-cc' successfully built!" || { echo "[-] Main compiler 'afl-cc' failed to built, set up a working build environment first!" ; exit 1 ; }
|
||||
@test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to built, likely you either have not llvm installed or you have not set LLVM_CONFIG pointing to e.g. llvm-config-11. See instrumenation/README.llvm.md how to do this. Highly recommended!"
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to built, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
|
||||
@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to built, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean all
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-*
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
-$(MAKE) -f GNUmakefile.llvm clean
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/afl_network_proxy clean
|
||||
@ -530,20 +523,22 @@ clean:
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
rm -rf qemu_mode/qemu-3.1.1
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
else
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
endif
|
||||
|
||||
.PHONY: deepclean
|
||||
deepclean: clean
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
git reset --hard >/dev/null 2>&1 || true
|
||||
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/afl_network_proxy
|
||||
@ -552,6 +547,7 @@ distrib: all
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
.PHONY: binary-only
|
||||
binary-only: all
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
@ -561,9 +557,10 @@ binary-only: all
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
.PHONY: source-only
|
||||
source-only: all
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
@#$(MAKE) -C examples/afl_network_proxy
|
||||
@ -573,8 +570,7 @@ source-only: all
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@printf "%s" ".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/^\.\///' >> $@
|
||||
@ -590,30 +586,29 @@ source-only: all
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
.PHONY: install
|
||||
install: all $(MANPAGES)
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
|
||||
if [ -f libAFLDriver.a ]; then install -m 644 libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libAFLQemuDriver.a ]; then install -m 644 libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
|
||||
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
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
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
@if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
|
||||
@if [ -f examples/aflpp_driver/libAFLDriver.a ]; then install -m 644 examples/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f examples/aflpp_driver/libAFLQemuDriver.a ]; then install -m 644 examples/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
-$(MAKE) -f GNUmakefile.llvm install
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin install
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
|
@ -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,66 @@ 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
|
||||
ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
||||
rm -f $(PROGS) afl-common.o ./afl-g++-fast ./afl-g*-fast.8 instrumentation/*.o
|
@ -26,10 +26,10 @@ DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MISC_PATH ?= $(PREFIX)/share/afl
|
||||
MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
@ -41,6 +41,7 @@ else
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^19' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
@ -78,13 +79,13 @@ ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation)
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
#TEST_MMAP = 1
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "0"
|
||||
$(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.)
|
||||
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE_XCODE)" "1"
|
||||
@ -224,7 +225,7 @@ else
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
|
||||
CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \
|
||||
CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
|
||||
@ -241,7 +242,7 @@ ifdef AFL_TRACE_PC
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
|
||||
override CXXFLAGS += -Wall -g -I ../include/ \
|
||||
override CXXFLAGS += -Wall -g -I ./include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros
|
||||
|
||||
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
|
||||
@ -283,7 +284,8 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so ../SanitizerCoverageLTO.so
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
@ -295,31 +297,31 @@ ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = no_build
|
||||
TARGETS = test_shm $(PROGS_ALWAYS) afl-cc.8
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-cc.8 test_build all_done
|
||||
endif
|
||||
|
||||
LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: test_shm
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: no_build
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
.PHONY: test_deps
|
||||
test_deps:
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE_XCODE)" "1"
|
||||
@ -333,148 +335,164 @@ 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 $@
|
||||
|
||||
../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-64.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); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt.o ;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
|
177
README.md
177
README.md
@ -4,7 +4,7 @@
|
||||
|
||||

|
||||
|
||||
Release Version: [2.68c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release Version: [2.67c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 3.00a
|
||||
|
||||
@ -22,6 +22,26 @@
|
||||
afl++ is a superior fork to Google's afl - more speed, more and better
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
## Major changes in afl++ 3.0
|
||||
|
||||
With afl++ 3.0 we introduced changes that break some previous afl and afl++
|
||||
behaviours:
|
||||
|
||||
* There are no llvm_mode and gcc_plugin subdirectories anymore and there is
|
||||
only one compiler: afl-cc. All previous compilers now symlink to this one
|
||||
compiler. All instrumentation source code is now in the `instrumentation/`
|
||||
folder.
|
||||
* qemu_mode got upgraded to QEMU 5.1, but to be able to build this a current
|
||||
ninja build tool version and python3 setuptools are required.
|
||||
qemu_mode also got new options like snapshotting, instrumenting specific
|
||||
shared libraries, etc. and QEMU 5.1 supports more CPU targets so this is
|
||||
worth it.
|
||||
* When instrumenting targets, afl-cc will not supersede optimizations. This
|
||||
allows to fuzz targets as same as they are built for debug or release.
|
||||
* afl-fuzz' `-i` option now descends into subdirectories.
|
||||
* afl-fuzz will skip over empty dictionaries and too large test cases instead
|
||||
of failing.
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Features](#important-features-of-afl)
|
||||
@ -39,7 +59,7 @@
|
||||
with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and
|
||||
Android support and much, much, much more.
|
||||
|
||||
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
|
||||
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | qemu_mode | unicorn_mode |
|
||||
| -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:|
|
||||
| NeverZero | x86[_64]| x(1) | (2) | x | x |
|
||||
| Persistent Mode | | x | x | x86[_64]/arm[64] | x |
|
||||
@ -47,9 +67,8 @@
|
||||
| CmpLog | | x | | x86[_64]/arm[64] | |
|
||||
| Selective Instrumentation| | x | x | (x)(3) | |
|
||||
| Non-Colliding Coverage | | x(4) | | (x)(5) | |
|
||||
| InsTrim | | x | | | |
|
||||
| Ngram prev_loc Coverage | | x(6) | | | |
|
||||
| Context Coverage | | x | | | |
|
||||
| Context Coverage | | x(6) | | | |
|
||||
| Auto Dictionary | | x(7) | | | |
|
||||
| Snapshot LKM Support | | x | | (x)(5) | |
|
||||
|
||||
@ -59,11 +78,11 @@
|
||||
4. with pcguard mode and LTO mode for LLVM >= 11
|
||||
5. upcoming, development in the branch
|
||||
6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
|
||||
7. only in LTO mode with LLVM >= 11
|
||||
7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x`
|
||||
|
||||
Among others, the following features and patches have been integrated:
|
||||
|
||||
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
||||
* NeverZero patch for afl-gcc, instrumentation, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
||||
* Persistent mode, deferred forkserver and in-memory fuzzing for qemu_mode
|
||||
* Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
||||
* The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
|
||||
@ -71,10 +90,9 @@
|
||||
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
|
||||
* The MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
|
||||
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
|
||||
* InsTrim, a CFG llvm_mode instrumentation implementation: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
|
||||
* C. Holler's afl-fuzz Python mutator module: [https://github.com/choller/afl](https://github.com/choller/afl)
|
||||
* Custom mutator by a library (instead of Python) by kyakdan
|
||||
* LAF-Intel/CompCov support for llvm_mode, qemu_mode and unicorn_mode (with enhanced capabilities)
|
||||
* LAF-Intel/CompCov support for instrumentation, qemu_mode and unicorn_mode (with enhanced capabilities)
|
||||
* Radamsa and honggfuzz mutators (as custom mutators).
|
||||
* QBDI mode to fuzz android native libraries via Quarkslab's [QBDI](https://github.com/QBDI/QBDI) framework
|
||||
* Frida and ptrace mode to fuzz binary-only libraries, etc.
|
||||
@ -88,7 +106,7 @@
|
||||
send a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to
|
||||
read this file.
|
||||
read this file - however this is not recommended!
|
||||
|
||||
## Branches
|
||||
|
||||
@ -105,13 +123,14 @@
|
||||
|
||||
## Help wanted
|
||||
|
||||
We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
|
||||
We were happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)
|
||||
and we will try to participate again in 2021!
|
||||
|
||||
We have several ideas we would like to see in AFL++ to make it even better.
|
||||
However, we already work on so many things that we do not have the time for
|
||||
all the big ideas.
|
||||
|
||||
This can be your way to support and contribute to AFL++ - extend it to
|
||||
This can be your way to support and contribute to AFL++ - extend it to do
|
||||
something cool.
|
||||
|
||||
We have an idea list in [docs/ideas.md](docs/ideas.md).
|
||||
@ -132,7 +151,7 @@ This image is automatically generated when a push to the stable repo happens.
|
||||
You will find your target source code in /src in the container.
|
||||
|
||||
If you want to build afl++ yourself you have many options.
|
||||
The easiest is to build and install everything:
|
||||
The easiest choice is to build and install everything:
|
||||
|
||||
```shell
|
||||
sudo apt install build-essential libtool-bin python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools llvm
|
||||
@ -142,9 +161,9 @@ sudo make install
|
||||
It is recommended to install the newest available gcc, clang and llvm-dev
|
||||
possible in your distribution!
|
||||
|
||||
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
|
||||
Note that "make distrib" also builds instrumentation, qemu_mode, unicorn_mode and
|
||||
more. If you just want plain afl++ then do "make all", however compiling and
|
||||
using at least llvm_mode is highly recommended for much better results -
|
||||
using at least instrumentation is highly recommended for much better results -
|
||||
hence in this case
|
||||
|
||||
```shell
|
||||
@ -156,7 +175,7 @@ These build targets exist:
|
||||
|
||||
* all: just the main afl++ binaries
|
||||
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap
|
||||
* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap
|
||||
* source-only: everything for source code fuzzing: instrumentation, libdislocator, libtokencap
|
||||
* distrib: everything (for both binary-only and source code fuzzing)
|
||||
* man: creates simple man pages from the help option of the programs
|
||||
* install: installs everything you have compiled with the build options above
|
||||
@ -212,18 +231,19 @@ If you have a binary-only target please skip to [#Instrumenting binary-only apps
|
||||
|
||||
Fuzzing source code is a three-step process.
|
||||
|
||||
1. compile the target with a special compiler that prepares the target to be
|
||||
1. Compile the target with a special compiler that prepares the target to be
|
||||
fuzzed efficiently. This step is called "instrumenting a target".
|
||||
2. Prepare the fuzzing by selecting and optimizing the input corpus for the
|
||||
target.
|
||||
3. perform the fuzzing of the target by randomly mutating input and assessing
|
||||
3. Perform the fuzzing of the target by randomly mutating input and assessing
|
||||
if a generated input was processed in a new path in the target binary.
|
||||
|
||||
### 1. Instrumenting that target
|
||||
|
||||
#### a) Selecting the best afl++ compiler for instrumenting the target
|
||||
|
||||
afl++ comes with different compilers and instrumentation options.
|
||||
afl++ comes with a central compiler `afl-cc` that incorporates various different
|
||||
kinds of compiler targets and and instrumentation options.
|
||||
The following evaluation flow will help you to select the best possible.
|
||||
|
||||
It is highly recommended to have the newest llvm version possible installed,
|
||||
@ -231,49 +251,62 @@ anything below 9 is not recommended.
|
||||
|
||||
```
|
||||
+--------------------------------+
|
||||
| clang/clang++ 11+ is available | --> use afl-clang-lto and afl-clang-lto++
|
||||
+--------------------------------+ see [llvm/README.lto.md](llvm/README.lto.md)
|
||||
| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++)
|
||||
+--------------------------------+ see [instrumentation/README.lto.md](instrumentation/README.lto.md)
|
||||
|
|
||||
| if not, or if the target fails with afl-clang-lto/++
|
||||
| if not, or if the target fails with LTO afl-clang-lto/++
|
||||
|
|
||||
v
|
||||
+---------------------------------+
|
||||
| clang/clang++ 3.3+ is available | --> use afl-clang-fast and afl-clang-fast++
|
||||
+---------------------------------+ see [llvm/README.md](llvm/README.md)
|
||||
| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
|
||||
+---------------------------------+ see [instrumentation/README.md](instrumentation/README.md)
|
||||
|
|
||||
| if not, or if the target fails with afl-clang-fast/++
|
||||
| if not, or if the target fails with LLVM afl-clang-fast/++
|
||||
|
|
||||
v
|
||||
+--------------------------------+
|
||||
| if you want to instrument only | -> use afl-gcc-fast and afl-gcc-fast++
|
||||
| parts of the target | see [gcc_plugin/README.md](gcc_plugin/README.md) and
|
||||
+--------------------------------+ [gcc_plugin/README.instrument_list.md](gcc_plugin/README.instrument_list.md)
|
||||
| if you want to instrument only | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
|
||||
| parts of the target | see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
|
||||
+--------------------------------+ [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
|
|
||||
| if not, or if you do not have a gcc with plugin support
|
||||
|
|
||||
v
|
||||
use afl-gcc and afl-g++ (or afl-clang and afl-clang++)
|
||||
use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang)
|
||||
```
|
||||
|
||||
Clickable README links for the chosen compiler:
|
||||
|
||||
* [afl-clang-lto](llvm/README.lto.md)
|
||||
* [afl-clang-fast](llvm/README.md)
|
||||
* [afl-gcc-fast](gcc_plugin/README.md)
|
||||
* afl-gcc has no README as it has no features
|
||||
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
|
||||
* [LLVM mode - afl-clang-fast](instrumentation/README.md)
|
||||
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
|
||||
* GCC mode (afl-gcc) has no README as it has no own features
|
||||
|
||||
You can select the mode for the afl-cc compiler by:
|
||||
1. passing --afl-MODE command line options to the compiler via CFLAGS/CXXFLAGS/CPPFLAGS
|
||||
2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
|
||||
afl-gcc-fast, afl-g++-fast
|
||||
3. using the environment variable AFL_CC_COMPILER with MODE
|
||||
|
||||
MODE can be one of: LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN
|
||||
(afl-g*-fast) or GCC (afl-gcc/afl-g++).
|
||||
|
||||
Because no afl specific command-line options are accepted (beside the
|
||||
--afl-MODE command), the compile-time tools make fairly broad use of environment
|
||||
variables, which can be listed with `afl-cc -hh` or by reading [docs/env_variables.md](docs/env_variables.md).
|
||||
|
||||
#### b) Selecting instrumentation options
|
||||
|
||||
The following options are available when you instrument with afl-clang-fast or
|
||||
afl-clang-lto:
|
||||
The following options are available when you instrument with LTO mode (afl-clang-fast/afl-clang-lto):
|
||||
|
||||
* Splitting integer, string, float and switch comparisons so afl++ can easier
|
||||
solve these. This is an important option if you do not have a very good
|
||||
and large input corpus. This technique is called laf-intel or COMPCOV.
|
||||
To use this set the following environment variable before compiling the
|
||||
target: `export AFL_LLVM_LAF_ALL=1`
|
||||
You can read more about this in [llvm/README.laf-intel.md](llvm/README.laf-intel.md)
|
||||
* A different technique (and usually a better than laf-intel) is to
|
||||
You can read more about this in [instrumentation/README.laf-intel.md](instrumentation/README.laf-intel.md)
|
||||
* A different technique (and usually a better one than laf-intel) is to
|
||||
instrument the target so that any compare values in the target are sent to
|
||||
afl++ which then tries to put these values into the fuzzing data at different
|
||||
locations. This technique is very fast and good - if the target does not
|
||||
@ -282,12 +315,13 @@ afl-clang-lto:
|
||||
If you want to use this technique, then you have to compile the target
|
||||
twice, once specifically with/for this mode, and pass this binary to afl-fuzz
|
||||
via the `-c` parameter.
|
||||
Not that you can compile also just a cmplog binary and use that for both
|
||||
however there will a performance penality.
|
||||
You can read more about this in [llvm_mode/README.cmplog.md](llvm_mode/README.cmplog.md)
|
||||
Note that you can compile also just a cmplog binary and use that for both
|
||||
however there will be a performance penality.
|
||||
You can read more about this in [instrumentation/README.cmplog.md](instrumentation/README.cmplog.md)
|
||||
|
||||
If you use afl-clang-fast, afl-clang-lto or afl-gcc-fast you have the option to
|
||||
selectively only instrument parts of the target that you are interested in:
|
||||
If you use LTO, LLVM or GCC_PLUGIN mode (afl-clang-fast/afl-clang-lto/afl-gcc-fast)
|
||||
you have the option to selectively only instrument parts of the target that you
|
||||
are interested in:
|
||||
|
||||
* To instrument only those parts of the target that you are interested in
|
||||
create a file with all the filenames of the source code that should be
|
||||
@ -299,29 +333,29 @@ selectively only instrument parts of the target that you are interested in:
|
||||
`export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per
|
||||
default to instrument unless noted (DENYLIST) or not perform instrumentation
|
||||
unless requested (ALLOWLIST).
|
||||
**NOTE:** In optimization functions might be inlined and then not match!
|
||||
see [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md)
|
||||
**NOTE:** During optimization functions might be inlined and then would not match!
|
||||
See [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the
|
||||
llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html)
|
||||
The llvm sancov format works with the allowlist/denylist feature of afl++
|
||||
however afl++ is more flexible in the format.
|
||||
however afl++'s format is more flexible.
|
||||
|
||||
There are many more options and modes available however these are most of the
|
||||
time less effective. See:
|
||||
* [llvm_mode/README.ctx.md](llvm_mode/README.ctx.md)
|
||||
* [llvm_mode/README.ngram.md](llvm_mode/README.ngram.md)
|
||||
* [llvm_mode/README.instrim.md](llvm_mode/README.instrim.md)
|
||||
* [instrumentation/README.ctx.md](instrumentation/README.ctx.md)
|
||||
* [instrumentation/README.ngram.md](instrumentation/README.ngram.md)
|
||||
* [instrumentation/README.instrim.md](instrumentation/README.instrim.md)
|
||||
|
||||
afl++ employs never zero counting in its bitmap. You can read more about this
|
||||
afl++ performs "never zero" counting in its bitmap. You can read more about this
|
||||
here:
|
||||
* [llvm_mode/README.neverzero.md](llvm_mode/README.neverzero.md)
|
||||
* [instrumentation/README.neverzero.md](instrumentation/README.neverzero.md)
|
||||
|
||||
#### c) Modify the target
|
||||
|
||||
If the target has features that make fuzzing more difficult, e.g.
|
||||
checksums, HMAC, etc. then modify the source code so that this is
|
||||
removed.
|
||||
This can even be done for productional source code be eliminating
|
||||
This can even be done for operational source code by eliminating
|
||||
these checks within this specific defines:
|
||||
|
||||
```
|
||||
@ -332,13 +366,15 @@ these checks within this specific defines:
|
||||
#endif
|
||||
```
|
||||
|
||||
All afl++ compilers will set this preprocessor definition automatically.
|
||||
|
||||
#### d) Instrument the target
|
||||
|
||||
In this step the target source code is compiled so that it can be fuzzed.
|
||||
|
||||
Basically you have to tell the target build system that the selected afl++
|
||||
compiler is used. Also - if possible - you should always configure the
|
||||
build system that the target is compiled statically and not dynamically.
|
||||
build system such that the target is compiled statically and not dynamically.
|
||||
How to do this is described below.
|
||||
|
||||
Then build the target. (Usually with `make`)
|
||||
@ -349,20 +385,22 @@ For `configure` build systems this is usually done by:
|
||||
`CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared`
|
||||
|
||||
Note that if you are using the (better) afl-clang-lto compiler you also have to
|
||||
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
|
||||
described in [llvm/README.lto.md](llvm/README.lto.md)
|
||||
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
|
||||
described in [instrumentation/README.lto.md](instrumentation/README.lto.md).
|
||||
|
||||
##### cmake
|
||||
|
||||
For `configure` build systems this is usually done by:
|
||||
`mkdir build; cd build; CC=afl-clang-fast CXX=afl-clang-fast++ cmake ..`
|
||||
|
||||
Some cmake scripts require something like `-DCMAKE_CC=... -DCMAKE_CXX=...`
|
||||
or `-DCMAKE_C_COMPILER=... DCMAKE_CPP_COMPILER=...` instead.
|
||||
For `cmake` build systems this is usually done by:
|
||||
`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..`
|
||||
|
||||
Note that if you are using the (better) afl-clang-lto compiler you also have to
|
||||
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
|
||||
described in [llvm/README.lto.md](llvm/README.lto.md)
|
||||
set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is
|
||||
described in [instrumentation/README.lto.md](instrumentation/README.lto.md).
|
||||
|
||||
##### meson
|
||||
|
||||
For meson you have to set the afl++ compiler with the very first command!
|
||||
`CC=afl-cc CXX=afl-c++ meson`
|
||||
|
||||
##### other build systems or if configure/cmake didn't work
|
||||
|
||||
@ -370,7 +408,7 @@ Sometimes cmake and configure do not pick up the afl++ compiler, or the
|
||||
ranlib/ar that is needed - because this was just not foreseen by the developer
|
||||
of the target. Or they have non-standard options. Figure out if there is a
|
||||
non-standard way to set this, otherwise set up the build normally and edit the
|
||||
generated build environment afterwards manually to point to the right compiler
|
||||
generated build environment afterwards manually to point it to the right compiler
|
||||
(and/or ranlib and ar).
|
||||
|
||||
#### d) Better instrumentation
|
||||
@ -383,12 +421,12 @@ This requires the usage of afl-clang-lto or afl-clang-fast.
|
||||
This is the so-called `persistent mode`, which is much, much faster but
|
||||
requires that you code a source file that is specifically calling the target
|
||||
functions that you want to fuzz, plus a few specific afl++ functions around
|
||||
it. See [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) for details.
|
||||
it. See [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md) for details.
|
||||
|
||||
Basically if you do not fuzz a target in persistent mode then you are just
|
||||
doing it for a hobby and not professionally :-)
|
||||
|
||||
### 2. Preparing the fuzzing
|
||||
### 2. Preparing the fuzzing campaign
|
||||
|
||||
As you fuzz the target with mutated input, having as diverse inputs for the
|
||||
target as possible improves the efficiency a lot.
|
||||
@ -401,7 +439,7 @@ reported bugs, test suites, random downloads from the internet, unit test
|
||||
case data - from all kind of PNG software.
|
||||
|
||||
If the input format is not known, you can also modify a target program to write
|
||||
away normal data it receives and processes to a file and use these.
|
||||
normal data it receives and processes to a file and use these.
|
||||
|
||||
#### b) Making the input corpus unique
|
||||
|
||||
@ -415,7 +453,7 @@ the run afl-cmin like this:
|
||||
`afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -d @@`
|
||||
Note that the INPUTFILE argument that the target program would read from has to be set as `@@`.
|
||||
|
||||
If the target reads from stdin instead, just omit the `@@` as this is the
|
||||
If the target reads from stdin instead, just omit the `@@` as this is the
|
||||
default.
|
||||
|
||||
#### c) Minimizing all corpus files
|
||||
@ -432,7 +470,7 @@ for i in *; do
|
||||
done
|
||||
```
|
||||
|
||||
This can also be parallelized, e.g. with `parallel`
|
||||
This step can also be parallelized, e.g. with `parallel`
|
||||
|
||||
#### Done!
|
||||
|
||||
@ -456,7 +494,7 @@ before the start of afl-fuzz as this improves performance by a x2 speed increase
|
||||
|
||||
#### a) Running afl-fuzz
|
||||
|
||||
Before to do even a test run of afl-fuzz execute `sudo afl-system-config` (on
|
||||
Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on
|
||||
the host if you execute afl-fuzz in a docker container). This reconfigures the
|
||||
system for optimal speed - which afl-fuzz checks and bails otherwise.
|
||||
Set `export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this check if you cannot
|
||||
@ -588,7 +626,7 @@ then terminate it. The main node will pick it up and make it available to the
|
||||
other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
|
||||
free core.
|
||||
|
||||
Note that you in nearly all cases you can never reach full coverage. A lot of
|
||||
Note that you in nearly all cases can never reach full coverage. A lot of
|
||||
functionality is usually behind options that were not activated or fuzz e.g.
|
||||
if you fuzz a library to convert image formats and your target is the png to
|
||||
tiff API then you will not touch any of the other library APIs and features.
|
||||
@ -607,7 +645,7 @@ switch or honggfuzz.
|
||||
|
||||
#### f) Improve the speed!
|
||||
|
||||
* Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase)
|
||||
* Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase)
|
||||
* If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
|
||||
* Linux: Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase)
|
||||
* Linux: Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure)
|
||||
@ -1035,7 +1073,6 @@ without feedback, bug reports, or patches from:
|
||||
Andrea Biondo Vincent Le Garrec
|
||||
Khaled Yakdan Kuang-che Wu
|
||||
Josephine Calliotte Konrad Welc
|
||||
Thomas Rooijakkers
|
||||
```
|
||||
|
||||
Thank you!
|
||||
|
@ -9,6 +9,20 @@ Want to stay in the loop on major new features? Join our mailing list by
|
||||
sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
|
||||
### Version ++3.00a (develop)
|
||||
- llvm_mode/ and gcc_plugin/ moved to instrumentation/
|
||||
- all compilers combined to afl-cc which emulates the previous ones
|
||||
- afl-llvm/gcc-rt.o merged into afl-compiler-rt.o
|
||||
- afl-fuzz
|
||||
- reading testcases from -i now descends into subdirectories
|
||||
- allow up to 4 -x command line options
|
||||
- loaded extras now have a duplicate protection
|
||||
- instrumentation
|
||||
- new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz
|
||||
-x dictionary of string comparisons found during compilation
|
||||
- not overriding -Ox or -fno-unroll-loops anymore
|
||||
|
||||
|
||||
### Version ++2.68c (release)
|
||||
- added the GSoC excellent afl++ grammar mutator by Shengtuo to our
|
||||
custom_mutators/ (see custom_mutators/README.md) - or get it here:
|
||||
|
104
docs/FAQ.md
104
docs/FAQ.md
@ -4,11 +4,11 @@
|
||||
|
||||
* [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl)
|
||||
* [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
|
||||
* [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service)
|
||||
* [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program)
|
||||
* [How do I fuzz a network service?](#how-to-fuzz-a-network-service)
|
||||
* [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program)
|
||||
* [What is an edge?](#what-is-an-edge)
|
||||
* [Why is my stability below 100%?](#why-is-my-stability-below-100)
|
||||
* [How can I improve the stability value?](#how-can-i-improve-the-stability-value)
|
||||
* [How can I improve the stability value](#how-can-i-improve-the-stability-value)
|
||||
|
||||
If you find an interesting or important question missing, submit it via
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues)
|
||||
@ -18,52 +18,51 @@ If you find an interesting or important question missing, submit it via
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting in
|
||||
2013/2014, and when he left Google end of 2017 he stopped developing it.
|
||||
|
||||
At the end of 2019 the Google fuzzing team took over maintenance of AFL, however
|
||||
it is only accepting PRs from the community and is not developing enhancements
|
||||
At the end of 2019 the Google fuzzing team took over maintance of AFL, however
|
||||
it is only accepting PR from the community and is not developing enhancements
|
||||
anymore.
|
||||
|
||||
In the second quarter of 2019, 1 1/2 year later when no further development of
|
||||
AFL had happened and it became clear there would none be coming, afl++
|
||||
was born, where initially community patches were collected and applied
|
||||
for bug fixes and enhancements. Then from various AFL spin-offs - mostly academic
|
||||
In the second quarter of 2019, 1 1/2 years after no further development of
|
||||
AFL had happened and it became clear there would be none coming, afl++
|
||||
was born, where initially first community patches were collected and applied
|
||||
for bugs and enhancements. Then from various AFL spin-offs - mostly academic
|
||||
research - features were integrated. This already resulted in a much advanced
|
||||
AFL.
|
||||
|
||||
Until the end of 2019 the afl++ team had grown to four active developers which
|
||||
then implemented their own research and features, making it now by far the most
|
||||
then implemented their own research and feature, making it now by far the most
|
||||
flexible and feature rich guided fuzzer available as open source.
|
||||
And in independent fuzzing benchmarks it is one of the best fuzzers available,
|
||||
e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html)
|
||||
|
||||
## How to improve the fuzzing speed?
|
||||
## How to improve the fuzzing speed
|
||||
|
||||
1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
|
||||
2. Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase)
|
||||
1. use [instrumentation](docs/README.llvm.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
|
||||
2. Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase)
|
||||
3. Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase)
|
||||
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
|
||||
5. Improve Linux kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system less secure)
|
||||
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
|
||||
5. Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure)
|
||||
6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem
|
||||
7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads)
|
||||
|
||||
## How do I fuzz a network service?
|
||||
|
||||
The short answer is - you cannot, at least not "out of the box".
|
||||
The short answer is - you cannot, at least "out of the box".
|
||||
|
||||
Using a network channel is inadequate for several reasons:
|
||||
- it has a slow-down of x10-20 on the fuzzing speed
|
||||
- it does not scale to fuzzing multiple instances easily,
|
||||
- instead of one initial data packet often a back-and-forth interplay of packets is needed for stateful protocols (which is totally unsupported by most coverage aware fuzzers).
|
||||
Using network has a slow-down of x10-20 on the fuzzing speed, does not scale,
|
||||
and finally usually it is more than one initial data packet but a back-and-forth
|
||||
which is totally unsupported by most coverage aware fuzzers.
|
||||
|
||||
The established method to fuzz network services is to modify the source code
|
||||
to read from a file or stdin (fd 0) (or even faster via shared memory, combine
|
||||
this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md)
|
||||
this with persistent mode [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md)
|
||||
and you have a performance gain of x10 instead of a performance loss of over
|
||||
x10 - that is a x100 difference!).
|
||||
x10 - that is a x100 difference!
|
||||
|
||||
If modifying the source is not an option (e.g. because you only have a binary
|
||||
and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD
|
||||
to emulate the network. This is also much faster than the real network would be.
|
||||
See [examples/socket_fuzzing/](../examples/socket_fuzzing/).
|
||||
to emulate the network. This is also much faster than network would be.
|
||||
See [examples/socket_fuzzing/](../examples/socket_fuzzing/)
|
||||
|
||||
There is an outdated afl++ branch that implements networking if you are
|
||||
desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) -
|
||||
@ -74,7 +73,7 @@ which allows you to define network state with different type of data packets.
|
||||
|
||||
If the GUI program can read the fuzz data from a file (via the command line,
|
||||
a fixed location or via an environment variable) without needing any user
|
||||
interaction then it would be suitable for fuzzing.
|
||||
interaction then then yes.
|
||||
|
||||
Otherwise it is not possible without modifying the source code - which is a
|
||||
very good idea anyway as the GUI functionality is a huge CPU/time overhead
|
||||
@ -83,13 +82,13 @@ for the fuzzing.
|
||||
So create a new `main()` that just reads the test case and calls the
|
||||
functionality for processing the input that the GUI program is using.
|
||||
|
||||
## What is an "edge"?
|
||||
## What is an "edge"
|
||||
|
||||
A program contains `functions`, `functions` contain the compiled machine code.
|
||||
The compiled machine code in a `function` can be in a single or many `basic blocks`.
|
||||
A `basic block` is the largest possible number of subsequent machine code
|
||||
instructions that has exactly one entrypoint (which can be be entered by multiple other basic blocks)
|
||||
and runs linearly without branching or jumping to other addresses (except at the end).
|
||||
instructions that runs independent, meaning it does not split up to different
|
||||
locations nor is it jumped into it from a different location:
|
||||
```
|
||||
function() {
|
||||
A:
|
||||
@ -99,7 +98,7 @@ function() {
|
||||
if (x) goto C; else goto D;
|
||||
C:
|
||||
some code
|
||||
goto E
|
||||
goto D
|
||||
D:
|
||||
some code
|
||||
goto B
|
||||
@ -109,7 +108,7 @@ function() {
|
||||
```
|
||||
Every code block between two jump locations is a `basic block`.
|
||||
|
||||
An `edge` is then the unique relationship between two directly connected `basic blocks` (from the
|
||||
An `edge` is then the unique relationship between two `basic blocks` (from the
|
||||
code example above):
|
||||
```
|
||||
Block A
|
||||
@ -124,9 +123,8 @@ code example above):
|
||||
Block E
|
||||
```
|
||||
Every line between two blocks is an `edge`.
|
||||
Note that a few basic block loop to itself, this too would be an edge.
|
||||
|
||||
## Why is my stability below 100%?
|
||||
## Why is my stability below 100%
|
||||
|
||||
Stability is measured by how many percent of the edges in the target are
|
||||
"stable". Sending the same input again and again should take the exact same
|
||||
@ -134,37 +132,37 @@ path through the target every time. If that is the case, the stability is 100%.
|
||||
|
||||
If however randomness happens, e.g. a thread reading other external data,
|
||||
reaction to timing, etc. then in some of the re-executions with the same data
|
||||
the edge coverage result will be different accross runs.
|
||||
the result in the edge information will be different accross runs.
|
||||
Those edges that change are then flagged "unstable".
|
||||
|
||||
The more "unstable" edges, the more difficult for afl++ to identify valid new
|
||||
paths.
|
||||
|
||||
A value above 90% is usually fine and a value above 80% is also still ok, and
|
||||
even a value above 20% can still result in successful finds of bugs.
|
||||
However, it is recommended that for values below 90% or 80% you should take
|
||||
countermeasures to improve stability.
|
||||
even above 20% can still result in successful finds of bugs.
|
||||
However, it is recommended that below 90% or 80% you should take measures to
|
||||
improve the stability.
|
||||
|
||||
## How can I improve the stability value?
|
||||
## How can I improve the stability value
|
||||
|
||||
For fuzzing a 100% stable target that covers all edges is the best case.
|
||||
For fuzzing a 100% stable target that covers all edges is the best.
|
||||
A 90% stable target that covers all edges is however better than a 100% stable
|
||||
target that ignores 10% of the edges.
|
||||
|
||||
With instability you basically have a partial coverage loss on an edge, with
|
||||
ignored functions you have a full loss on that edges.
|
||||
ignore you have a full loss on that edge.
|
||||
|
||||
There are functions that are unstable, but also provide value to coverage, eg
|
||||
init functions that use fuzz data as input for example.
|
||||
If however a function that has nothing to do with the input data is the
|
||||
source of instability, e.g. checking jitter, or is a hash map function etc.
|
||||
then it should not be instrumented.
|
||||
If however it is a function that has nothing to do with the input data is the
|
||||
source, e.g. checking jitter, or is a hash map function etc. then it should
|
||||
not be instrumented.
|
||||
|
||||
To be able to exclude these functions (based on AFL++'s measured stability)
|
||||
the following process will allow to identify functions with variable edges.
|
||||
To be able to make this decision the following process will allow you to
|
||||
identify the functions with variable edges so you can make this decision.
|
||||
|
||||
Four steps are required to do this and it also requires quite some knowledge
|
||||
of coding and/or disassembly and is effectively possible only with
|
||||
Four steps are required to do this and requires quite some knowledge of
|
||||
coding and/or disassembly and it is only effectively possible with
|
||||
afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
|
||||
|
||||
1. First step: Identify which edge ID numbers are unstable
|
||||
@ -173,7 +171,7 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
|
||||
The out/fuzzer_stats file will then show the edge IDs that were identified
|
||||
as unstable.
|
||||
|
||||
2. Second step: Find the responsible function(s).
|
||||
2. Second step: Find the responsible function.
|
||||
|
||||
a) For LTO instrumented binaries this can be documented during compile
|
||||
time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`.
|
||||
@ -182,10 +180,10 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
|
||||
|
||||
b) For PCGUARD instrumented binaries it is much more difficult. Here you
|
||||
can either modify the __sanitizer_cov_trace_pc_guard function in
|
||||
llvm_mode/afl-llvm-rt.o.c to write a backtrace to a file if the ID in
|
||||
instrumentation/afl-llvm-rt.o.c to write a backtrace to a file if the ID in
|
||||
__afl_area_ptr[*guard] is one of the unstable edge IDs.
|
||||
(Example code is already there).
|
||||
Then recompile and reinstall llvm_mode and rebuild your target.
|
||||
Then recompile and reinstall instrumentation and rebuild your target.
|
||||
Run the recompiled target with afl-fuzz for a while and then check the
|
||||
file that you wrote with the backtrace information.
|
||||
Alternatively you can use `gdb` to hook __sanitizer_cov_trace_pc_guard_init
|
||||
@ -193,20 +191,20 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
|
||||
and set a write breakpoint to that address (`watch 0x.....`).
|
||||
|
||||
c) in all other instrumentation types this is not possible. So just
|
||||
recompile with the two mentioned above. This is just for
|
||||
recompile with the the two mentioned above. This is just for
|
||||
identifying the functions that have unstable edges.
|
||||
|
||||
3. Third step: create a text file with the filenames/functions
|
||||
|
||||
Identify which source code files contain the functions that you need to
|
||||
remove from instrumentation, or just specify the functions you want to
|
||||
skip for instrumentation. Note that optimization might inline functions!
|
||||
skip instrumenting. Note that optimization might inline functions!
|
||||
|
||||
Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md)
|
||||
Simply follow this document on how to do this: [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
If PCGUARD is used, then you need to follow this guide (needs llvm 12+!):
|
||||
[http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
|
||||
|
||||
Only exclude those functions from instrumentation that provide no value
|
||||
Only deny those functions from instrumentation that provide no value
|
||||
for coverage - that is if it does not process any fuzz data directly
|
||||
or indirectly (e.g. hash maps, thread management etc.).
|
||||
If however a function directly or indirectly handles fuzz data then you
|
||||
|
@ -24,7 +24,7 @@ There are no special dependencies to speak of; you will need GNU make and a
|
||||
working compiler (gcc or clang). Some of the optional scripts bundled with the
|
||||
program may depend on bash, gdb, and similar basic tools.
|
||||
|
||||
If you are using clang, please review llvm_mode/README.md; the LLVM
|
||||
If you are using clang, please review README.llvm.md; the LLVM
|
||||
integration mode can offer substantial performance gains compared to the
|
||||
traditional approach.
|
||||
|
||||
@ -52,10 +52,10 @@ sudo gmake install
|
||||
Keep in mind that if you are using csh as your shell, the syntax of some of the
|
||||
shell commands given in the README.md and other docs will be different.
|
||||
|
||||
The `llvm_mode` requires a dynamically linked, fully-operational installation of
|
||||
The `llvm` requires a dynamically linked, fully-operational installation of
|
||||
clang. At least on FreeBSD, the clang binaries are static and do not include
|
||||
some of the essential tools, so if you want to make it work, you may need to
|
||||
follow the instructions in llvm_mode/README.md.
|
||||
follow the instructions in README.llvm.md.
|
||||
|
||||
Beyond that, everything should work as advertised.
|
||||
|
||||
@ -97,27 +97,24 @@ and definitely don't look POSIX-compliant. This means two things:
|
||||
User emulation mode of QEMU does not appear to be supported on MacOS X, so
|
||||
black-box instrumentation mode (`-Q`) will not work.
|
||||
|
||||
The llvm_mode requires a fully-operational installation of clang. The one that
|
||||
The llvm instrumentation requires a fully-operational installation of clang. The one that
|
||||
comes with Xcode is missing some of the essential headers and helper tools.
|
||||
See llvm_mode/README.md for advice on how to build the compiler from scratch.
|
||||
See README.llvm.md for advice on how to build the compiler from scratch.
|
||||
|
||||
## 4. Linux or *BSD on non-x86 systems
|
||||
|
||||
Standard build will fail on non-x86 systems, but you should be able to
|
||||
leverage two other options:
|
||||
|
||||
- The LLVM mode (see llvm_mode/README.md), which does not rely on
|
||||
- The LLVM mode (see README.llvm.md), which does not rely on
|
||||
x86-specific assembly shims. It's fast and robust, but requires a
|
||||
complete installation of clang.
|
||||
- The QEMU mode (see qemu_mode/README.md), which can be also used for
|
||||
fuzzing cross-platform binaries. It's slower and more fragile, but
|
||||
can be used even when you don't have the source for the tested app.
|
||||
|
||||
If you're not sure what you need, you need the LLVM mode. To get it, try:
|
||||
|
||||
```bash
|
||||
AFL_NO_X86=1 gmake && gmake -C llvm_mode
|
||||
```
|
||||
If you're not sure what you need, you need the LLVM mode, which is built by
|
||||
default.
|
||||
|
||||
...and compile your target program with afl-clang-fast or afl-clang-fast++
|
||||
instead of the traditional afl-gcc or afl-clang wrappers.
|
||||
|
@ -5,13 +5,25 @@
|
||||
users or for some types of custom fuzzing setups. See README.md for the general
|
||||
instruction manual.
|
||||
|
||||
## 1) Settings for afl-gcc, afl-clang, and afl-as - and gcc_plugin afl-gcc-fast
|
||||
## 1) Settings for all compilers
|
||||
|
||||
Because they can't directly accept command-line options, the compile-time
|
||||
tools make fairly broad use of environmental variables:
|
||||
Starting with afl++ 3.0 there is only one compiler: afl-cc
|
||||
To select the different instrumentation modes this can be done by
|
||||
1. passing --afl-MODE command line options to the compiler
|
||||
2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
|
||||
afl-gcc-fast, afl-g++-fast
|
||||
3. using the environment variable AFL_CC_COMPILER with MODE
|
||||
|
||||
- Most afl tools do not print any output if stdout/stderr are redirected.
|
||||
If you want to save the output in a file then set the AFL_DEBUG
|
||||
MODE can one of LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN
|
||||
(afl-g*-fast) or GCC (afl-gcc/afl-g++).
|
||||
|
||||
Because beside the --afl-MODE command no afl specific command-line options
|
||||
are accepted, the compile-time tools make fairly broad use of environmental
|
||||
variables:
|
||||
|
||||
- Most afl tools do not print any ouput if stout/stderr are redirected.
|
||||
If you want to have the output into a file then set the AFL_DEBUG
|
||||
environment variable.
|
||||
This is sadly necessary for various build processes which fail otherwise.
|
||||
|
||||
@ -24,6 +36,8 @@ tools make fairly broad use of environmental variables:
|
||||
will cause problems in programs built with -Werror, simply because -O3
|
||||
enables more thorough code analysis and can spew out additional warnings.
|
||||
To disable optimizations, set AFL_DONT_OPTIMIZE.
|
||||
However if -O... and/or -fno-unroll-loops are set, these are not
|
||||
overriden.
|
||||
|
||||
- Setting AFL_USE_ASAN automatically enables ASAN, provided that your
|
||||
compiler supports that. Note that fuzzing with ASAN is mildly challenging
|
||||
@ -44,7 +58,7 @@ tools make fairly broad use of environmental variables:
|
||||
you instrument hand-written assembly when compiling clang code by plugging
|
||||
a normalizer into the chain. (There is no equivalent feature for GCC.)
|
||||
|
||||
- Setting AFL_INST_RATIO to a percentage between 0% and 100% controls the
|
||||
- Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the
|
||||
probability of instrumenting every branch. This is (very rarely) useful
|
||||
when dealing with exceptionally complex programs that saturate the output
|
||||
bitmap. Examples include v8, ffmpeg, and perl.
|
||||
@ -55,19 +69,16 @@ tools make fairly broad use of environmental variables:
|
||||
Setting AFL_INST_RATIO to 0 is a valid choice. This will instrument only
|
||||
the transitions between function entry points, but not individual branches.
|
||||
|
||||
Note that this is an outdated variable. A few instances (e.g. afl-gcc)
|
||||
still support these, but state-of-the-art (e.g. LLVM LTO and LLVM PCGUARD)
|
||||
do not need this.
|
||||
|
||||
- AFL_NO_BUILTIN causes the compiler to generate code suitable for use with
|
||||
libtokencap.so (but perhaps running a bit slower than without the flag).
|
||||
|
||||
- TMPDIR is used by afl-as for temporary files; if this variable is not set,
|
||||
the tool defaults to /tmp.
|
||||
|
||||
- Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented
|
||||
assembly files. Useful for troubleshooting problems or understanding how
|
||||
the tool works. To get them in a predictable place, try something like:
|
||||
|
||||
mkdir assembly_here
|
||||
TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all
|
||||
|
||||
- If you are a weird person that wants to compile and instrument asm
|
||||
text files then use the AFL_AS_FORCE_INSTRUMENT variable:
|
||||
AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo
|
||||
@ -78,19 +89,24 @@ tools make fairly broad use of environmental variables:
|
||||
- Setting AFL_CAL_FAST will speed up the initial calibration, if the
|
||||
application is very slow
|
||||
|
||||
## 2) Settings for afl-clang-fast / afl-clang-fast++ / afl-gcc-fast / afl-g++-fast
|
||||
## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++
|
||||
|
||||
The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset
|
||||
The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset
|
||||
of the settings discussed in section #1, with the exception of:
|
||||
|
||||
- LLVM modes support `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` which will
|
||||
write all constant string comparisons to this file to be used with
|
||||
afl-fuzz' `-x` option.
|
||||
|
||||
- AFL_AS, since this toolchain does not directly invoke GNU as.
|
||||
|
||||
- TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are
|
||||
created.
|
||||
|
||||
- AFL_INST_RATIO, as we by default use collision free instrumentation.
|
||||
- AFL_INST_RATIO, as we by default collision free instrumentation is used.
|
||||
Not all passes support this option though as it is an outdated feature.
|
||||
|
||||
Then there are a few specific features that are only available in llvm_mode:
|
||||
Then there are a few specific features that are only available in instrumentation:
|
||||
|
||||
### Select the instrumentation mode
|
||||
|
||||
@ -121,7 +137,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
None of the following options are necessary to be used and are rather for
|
||||
manual use (which only ever the author of this LTO implementation will use).
|
||||
These are used if several seperated instrumentations are performed which
|
||||
These are used if several seperated instrumentation are performed which
|
||||
are then later combined.
|
||||
|
||||
- AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given
|
||||
@ -136,7 +152,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
- AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written
|
||||
into the instrumentation is set in a global variable
|
||||
|
||||
See llvm_mode/README.LTO.md for more information.
|
||||
See instrumentation/README.LTO.md for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
@ -154,7 +170,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
See llvm_mode/README.instrim.md
|
||||
See instrumentation/README.instrim.md
|
||||
|
||||
### NGRAM
|
||||
|
||||
@ -165,7 +181,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ctx.md
|
||||
See instrumentation/README.ctx.md
|
||||
|
||||
### CTX
|
||||
|
||||
@ -176,7 +192,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ngram.md
|
||||
See instrumentation/README.ngram.md
|
||||
|
||||
### LAF-INTEL
|
||||
|
||||
@ -196,17 +212,17 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
- Setting AFL_LLVM_LAF_ALL sets all of the above
|
||||
|
||||
See llvm_mode/README.laf-intel.md for more information.
|
||||
See instrumentation/README.laf-intel.md for more information.
|
||||
|
||||
### INSTRUMENT LIST (selectively instrument files and functions)
|
||||
|
||||
This feature allows selective instrumentation of the source
|
||||
This feature allows selectively instrumentation of the source
|
||||
|
||||
- Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or
|
||||
function will only instrument (or skip) those files that match the names
|
||||
listed in the specified file.
|
||||
|
||||
See llvm_mode/README.instrument_list.md for more information.
|
||||
See instrumentation/README.instrument_list.md for more information.
|
||||
|
||||
### NOT_ZERO
|
||||
|
||||
@ -220,27 +236,34 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
test. If the target performs only few loops then this will give a
|
||||
small performance boost.
|
||||
|
||||
See llvm_mode/README.neverzero.md
|
||||
See instrumentation/README.neverzero.md
|
||||
|
||||
### CMPLOG
|
||||
|
||||
- Setting AFL_LLVM_CMPLOG=1 during compilation will tell afl-clang-fast to
|
||||
produce a CmpLog binary. See llvm_mode/README.cmplog.md
|
||||
produce a CmpLog binary. See instrumentation/README.cmplog.md
|
||||
|
||||
See llvm_mode/README.neverzero.md
|
||||
See instrumentation/README.neverzero.md
|
||||
|
||||
Then there are a few specific features that are only available in the gcc_plugin:
|
||||
## 3) Settings for GCC / GCC_PLUGIN modes
|
||||
|
||||
### INSTRUMENT_FILE
|
||||
Then there are a few specific features that are only available in GCC and
|
||||
GCC_PLUGIN mode.
|
||||
|
||||
This feature allows selective instrumentation of the source
|
||||
- Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented
|
||||
assembly files. Useful for troubleshooting problems or understanding how
|
||||
the tool works. (GCC mode only)
|
||||
To get them in a predictable place, try something like:
|
||||
|
||||
- Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those
|
||||
files that match the names listed in this file (one filename per line).
|
||||
mkdir assembly_here
|
||||
TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all
|
||||
|
||||
- Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those
|
||||
files that match the names listed in this file (one filename per line).
|
||||
See gcc_plugin/README.instrument_list.md for more information.
|
||||
(GCC_PLUGIN mode only)
|
||||
|
||||
## 3) Settings for afl-fuzz
|
||||
## 4) Settings for afl-fuzz
|
||||
|
||||
The main fuzzer binary accepts several options that disable a couple of sanity
|
||||
checks or alter some of the more exotic semantics of the tool:
|
||||
@ -278,14 +301,6 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
don't want AFL to spend too much time classifying that stuff and just
|
||||
rapidly put all timeouts in that bin.
|
||||
|
||||
- Setting AFL_FORKSRV_INIT_TMOUT allows yout to specify a different timeout
|
||||
to wait for the forkserver to spin up. The default is the `-t` value times
|
||||
`FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
|
||||
default would wait `1000` milis. Setting a different time here is useful
|
||||
if the target has a very slow startup time, for example when doing
|
||||
full-system fuzzing or emulation, but you don't want the actual runs
|
||||
to wait too long for timeouts.
|
||||
|
||||
- AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics.
|
||||
This can be useful to speed up the fuzzing of text-based file formats.
|
||||
|
||||
@ -377,22 +392,12 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
Note that this setting inhibits some of the user-friendly diagnostics
|
||||
normally done when starting up the forkserver and causes a pretty
|
||||
significant performance drop.
|
||||
|
||||
- Setting AFL_MAX_DET_EXTRAS changes the count of dictionary entries/extras
|
||||
(default 200), after which the entries will be used probabilistically.
|
||||
So, if the dict/extras file (`-x`) contains more tokens than this threshold,
|
||||
not all of the tokens will be used in each fuzzing step, every time.
|
||||
Instead, there is a chance that the entry will be skipped during fuzzing.
|
||||
This makes sure that the fuzzer doesn't spend all its time only inserting
|
||||
the extras, but will still do other mutations. However, it decreases the
|
||||
likelihood for each token to be inserted, before the next queue entry is fuzzed.
|
||||
Either way, all tokens will be used eventually, in a longer fuzzing campaign.
|
||||
|
||||
- Outdated environment variables that are that not supported anymore:
|
||||
AFL_DEFER_FORKSRV
|
||||
AFL_PERSISTENT
|
||||
|
||||
## 4) Settings for afl-qemu-trace
|
||||
## 5) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
|
||||
@ -446,7 +451,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
stack pointer in which QEMU can find the return address when `start addr` is
|
||||
hitted.
|
||||
|
||||
## 5) Settings for afl-cmin
|
||||
## 6) Settings for afl-cmin
|
||||
|
||||
The corpus minimization script offers very little customization:
|
||||
|
||||
@ -472,12 +477,12 @@ to match when minimizing crashes. This will make minimization less useful, but
|
||||
may prevent the tool from "jumping" from one crashing condition to another in
|
||||
very buggy software. You probably want to combine it with the -e flag.
|
||||
|
||||
## 7) Settings for afl-analyze
|
||||
## 8) Settings for afl-analyze
|
||||
|
||||
You can set AFL_ANALYZE_HEX to get file offsets printed as hexadecimal instead
|
||||
of decimal.
|
||||
|
||||
## 8) Settings for libdislocator
|
||||
## 9) Settings for libdislocator
|
||||
|
||||
The library honors these environmental variables:
|
||||
|
||||
@ -499,12 +504,12 @@ The library honors these environmental variables:
|
||||
- AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to
|
||||
max_align_t to be compliant with the C standard.
|
||||
|
||||
## 9) Settings for libtokencap
|
||||
## 10) Settings for libtokencap
|
||||
|
||||
This library accepts AFL_TOKEN_FILE to indicate the location to which the
|
||||
discovered tokens should be written.
|
||||
|
||||
## 10) Third-party variables set by afl-fuzz & other tools
|
||||
## 11) Third-party variables set by afl-fuzz & other tools
|
||||
|
||||
Several variables are not directly interpreted by afl-fuzz, but are set to
|
||||
optimal values if not already present in the environment:
|
||||
|
@ -3,49 +3,6 @@
|
||||
In the following, we describe a variety of ideas that could be implemented
|
||||
for future AFL++ versions.
|
||||
|
||||
For GSOC2020 interested students please see
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues/208](https://github.com/AFLplusplus/AFLplusplus/issues/208)
|
||||
|
||||
## Flexible Grammar Mutator (currently in development)
|
||||
|
||||
Currently, AFL++'s mutation does not have deeper knowledge about the fuzzed
|
||||
binary, apart from feedback, even though the developer may have insights
|
||||
about the target.
|
||||
|
||||
A developer may choose to provide dictionaries and implement own mutations
|
||||
in python or C, but an easy mutator that behaves according to a given grammar,
|
||||
does not exist.
|
||||
|
||||
State-of-the-art research on grammar fuzzing has some problems in their
|
||||
implementations like code quality, scalability, or ease of use and other
|
||||
common issues of the academic code.
|
||||
|
||||
We aim to develop a pluggable grammar mutator for afl++ that combines
|
||||
various results.
|
||||
|
||||
Mentor: andreafioraldi
|
||||
|
||||
## perf-fuzz Linux Kernel Module
|
||||
|
||||
Expand on [snapshot LKM](https://github.com/AFLplusplus/AFL-Snapshot-LKM)
|
||||
To make it thread safe, can snapshot several processes at once and increase
|
||||
overall performance.
|
||||
|
||||
Mentor: any
|
||||
|
||||
## QEMU 5-based Instrumentation
|
||||
|
||||
First tests to use QEMU 4 for binary-only AFL++ showed that caching behavior
|
||||
changed, which vastly decreases fuzzing speeds.
|
||||
|
||||
In this task test if QEMU 5 performs better and port the afl++ QEMU 3.1
|
||||
patches to QEMU 5.
|
||||
|
||||
Understanding the current instrumentation and fixing the current caching
|
||||
issues will be needed.
|
||||
|
||||
Mentor: andreafioraldi
|
||||
|
||||
## WASM Instrumentation
|
||||
|
||||
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
|
||||
@ -66,20 +23,6 @@ Either improve a single mutator thorugh learning of many different bugs
|
||||
|
||||
Mentor: domenukk
|
||||
|
||||
## Reengineer `afl-fuzz` as Thread Safe, Embeddable Library (currently in development)
|
||||
|
||||
Right now, afl-fuzz is single threaded, cannot safely be embedded in tools,
|
||||
and not multi-threaded. It makes use of a large number of globals, must always
|
||||
be the parent process and exec child processes.
|
||||
Instead, afl-fuzz could be refactored to contain no global state and globals.
|
||||
This allows for different use cases that could be implemented during this
|
||||
project.
|
||||
Note that in the mean time a lot has happened here already, but e.g. making
|
||||
it all work and implement multithreading in afl-fuzz ... there is still quite
|
||||
some work to do.
|
||||
|
||||
Mentor: hexcoder- or vanhauser-thc
|
||||
|
||||
## Collision-free Binary-Only Maps
|
||||
|
||||
AFL++ supports collison-free maps using an LTO (link-time-optimization) pass.
|
||||
|
@ -30,10 +30,10 @@ Check out the `fuzzer_stats` file in the AFL output dir or try `afl-whatsup`.
|
||||
It could be important - consult docs/status_screen.md right away!
|
||||
|
||||
## Know your target? Convert it to persistent mode for a huge performance gain!
|
||||
Consult section #5 in llvm_mode/README.md for tips.
|
||||
Consult section #5 in README.llvm.md for tips.
|
||||
|
||||
## Using clang?
|
||||
Check out llvm_mode/ for a faster alternative to afl-gcc!
|
||||
Check out instrumentation/ for a faster alternative to afl-gcc!
|
||||
|
||||
## Did you know that AFL can fuzz closed-source or cross-platform binaries?
|
||||
Check out qemu_mode/README.md and unicorn_mode/README.md for more.
|
||||
|
@ -51,7 +51,7 @@ a file.
|
||||
## 3. Use LLVM instrumentation
|
||||
|
||||
When fuzzing slow targets, you can gain 20-100% performance improvement by
|
||||
using the LLVM-based instrumentation mode described in [the llvm_mode README](../llvm_mode/README.md).
|
||||
using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md).
|
||||
Note that this mode requires the use of clang and will not work with GCC.
|
||||
|
||||
The LLVM mode also offers a "persistent", in-process fuzzing mode that can
|
||||
@ -62,12 +62,12 @@ modes require you to edit the source code of the fuzzed program, but the
|
||||
changes often amount to just strategically placing a single line or two.
|
||||
|
||||
If there are important data comparisons performed (e.g. `strcmp(ptr, MAGIC_HDR)`)
|
||||
then using laf-intel (see llvm_mode/README.laf-intel.md) will help `afl-fuzz` a lot
|
||||
then using laf-intel (see instrumentation/README.laf-intel.md) will help `afl-fuzz` a lot
|
||||
to get to the important parts in the code.
|
||||
|
||||
If you are only interested in specific parts of the code being fuzzed, you can
|
||||
instrument_files the files that are actually relevant. This improves the speed and
|
||||
accuracy of afl. See llvm_mode/README.instrument_list.md
|
||||
accuracy of afl. See instrumentation/README.instrument_list.md
|
||||
|
||||
Also use the InsTrim mode on larger binaries, this improves performance and
|
||||
coverage a lot.
|
||||
@ -110,7 +110,7 @@ e.g.:
|
||||
https://launchpad.net/libeatmydata
|
||||
|
||||
In programs that are slow due to unavoidable initialization overhead, you may
|
||||
want to try the LLVM deferred forkserver mode (see llvm_mode/README.md),
|
||||
want to try the LLVM deferred forkserver mode (see README.llvm.md),
|
||||
which can give you speed gains up to 10x, as mentioned above.
|
||||
|
||||
Last but not least, if you are using ASAN and the performance is unacceptable,
|
||||
|
@ -52,7 +52,7 @@ options.
|
||||
Provides an evolutionary instrumentation-guided fuzzing harness that allows
|
||||
some programs to be fuzzed without the fork / execve overhead. (Similar
|
||||
functionality is now available as the "persistent" feature described in
|
||||
[the llvm_mode readme](../llvm_mode/README.md))
|
||||
[the llvm_mode readme](../instrumentation/README.llvm.md))
|
||||
|
||||
http://llvm.org/docs/LibFuzzer.html
|
||||
|
||||
@ -245,7 +245,7 @@ https://code.google.com/p/address-sanitizer/wiki/AsanCoverage#Coverage_counters
|
||||
### AFL JS (Han Choongwoo)
|
||||
|
||||
One-off optimizations to speed up the fuzzing of JavaScriptCore (now likely
|
||||
superseded by LLVM deferred forkserver init - see llvm_mode/README.md).
|
||||
superseded by LLVM deferred forkserver init - see README.llvm.md).
|
||||
|
||||
https://github.com/tunz/afl-fuzz-js
|
||||
|
||||
|
@ -324,7 +324,7 @@ there are several things to look at:
|
||||
- Multiple threads executing at once in semi-random order. This is harmless
|
||||
when the 'stability' metric stays over 90% or so, but can become an issue
|
||||
if not. Here's what to try:
|
||||
* Use afl-clang-fast from [llvm_mode](../llvm_mode/) - it uses a thread-local tracking
|
||||
* Use afl-clang-fast from [instrumentation](../instrumentation/) - it uses a thread-local tracking
|
||||
model that is less prone to concurrency issues,
|
||||
* See if the target can be compiled or run without threads. Common
|
||||
`./configure` options include `--without-threads`, `--disable-pthreads`, or
|
||||
|
@ -47,7 +47,7 @@ Here's a quick overview of the stuff you can find in this directory:
|
||||
|
||||
Note that the minimize_corpus.sh tool has graduated from the examples/
|
||||
directory and is now available as ../afl-cmin. The LLVM mode has likewise
|
||||
graduated to ../llvm_mode/*.
|
||||
graduated to ../instrumentation/*.
|
||||
|
||||
Most of the tools in this directory are meant chiefly as examples that need to
|
||||
be tweaked for your specific needs. They come with some basic documentation,
|
||||
|
@ -27,7 +27,7 @@ EOF
|
||||
# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
|
||||
clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
|
||||
# Build afl-llvm-rt.o.c from the AFL distribution.
|
||||
clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
|
||||
clang -c -w $AFL_HOME/instrumentation/afl-llvm-rt.o.c
|
||||
# Build this file, link it with afl-llvm-rt.o.o and the target code.
|
||||
clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
|
||||
# Run AFL:
|
||||
|
@ -1,159 +0,0 @@
|
||||
#
|
||||
# american fuzzy lop++ - GCC plugin instrumentation
|
||||
# -----------------------------------------------
|
||||
#
|
||||
# Written by Austin Seipp <aseipp@pobox.com> and
|
||||
# Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski and
|
||||
# Heiko Eißfeldt <heiko@hexco.de>
|
||||
#
|
||||
# GCC integration design is based on the LLVM design, which comes
|
||||
# from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
VERSION:sh= grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS = -Wall -I../include -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
|
||||
CXXFLAGS = -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS = $(CXXFLAGS) -Wall
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
||||
MYCC=$(CC:clang=gcc)
|
||||
MYCXX=$(CXX:clang++=g++)
|
||||
|
||||
PLUGIN_PATH = $(shell $(MYCC) -print-file-name=plugin)
|
||||
PLUGIN_PATH:sh= $(MYCC) -print-file-name=plugin
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(PLUGIN_PATH)/include"
|
||||
HASH=\#
|
||||
|
||||
GCCVER = $(shell $(MYCC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCVER:sh= gcc --version 2>/dev/null | awk 'NR == 1 {print $$NF}'
|
||||
GCCBINDIR = $(shell dirname `command -v $(MYCC)` 2>/dev/null )
|
||||
GCCBINDIR:sh= dirname `command -v $(MYCC)` 2>/dev/null
|
||||
|
||||
_SHMAT_OK= $(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )
|
||||
_SHMAT_OK:sh= echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2
|
||||
|
||||
IGNORE_MMAP=$(TEST_MMAP:1=0)
|
||||
__SHMAT_OK=$(_SHMAT_OK)$(IGNORE_MMAP)
|
||||
___SHMAT_OK=$(__SHMAT_OK:10=0)
|
||||
SHMAT_OK=$(___SHMAT_OK:1=1)
|
||||
_CFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
CFLAGS_ADD=$(_CFLAGS_ADD:0=-DUSEMMAP=1)
|
||||
|
||||
_LDFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt)
|
||||
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
PROGS = ../afl-gcc-pass.so ../afl-gcc-fast ../afl-gcc-rt.o
|
||||
|
||||
all: test_shm test_deps $(PROGS) ../afl-gcc-fast.8 test_build all_done
|
||||
|
||||
debug:
|
||||
@echo _SHMAT_OK = $(_SHMAT_OK)
|
||||
@echo IGNORE_MMAP = $(IGNORE_MMAP)
|
||||
@echo __SHMAT_OK = $(__SHMAT_OK)
|
||||
@echo ___SHMAT_OK = $(___SHMAT_OK)
|
||||
@echo SHMAT_OK = $(SHMAT_OK)
|
||||
|
||||
test_shm:
|
||||
@if [ "$(SHMAT_OK)" == "1" ]; then \
|
||||
echo "[+] shmat seems to be working."; \
|
||||
rm -f .test2; \
|
||||
else \
|
||||
echo "[-] shmat seems not to be working, switching to mmap implementation"; \
|
||||
fi
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(MYCC)'..."
|
||||
@type $(MYCC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(MYCC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(MYCC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(MYCC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(MYCC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-gcc-fast: afl-gcc-fast.c afl-common.o
|
||||
$(MYCC) -DAFL_GCC_CC=\"$(MYCC)\" -DAFL_GCC_CXX=\"$(MYCXX)\" $(CFLAGS) afl-gcc-fast.c afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-gcc-fast ../afl-g++-fast
|
||||
|
||||
../afl-gcc-pass.so: afl-gcc-pass.so.cc
|
||||
$(MYCXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared afl-gcc-pass.so.cc -o $@
|
||||
|
||||
../afl-gcc-rt.o: afl-gcc-rt.o.c
|
||||
$(MYCC) $(CFLAGS) -fPIC -c afl-gcc-rt.o.c -o $@
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
@ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
@ASAN_OPTIONS=detect_leaks=0 echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@trap 'rm .test-instr0 .test-instr1' 0;if cmp -s .test-instr0 .test-instr1; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-gcc-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
../afl-gcc-fast.8: ../afl-gcc-fast
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-gcc-fast.8 ../afl-g++-fast.8
|
||||
|
||||
install: all
|
||||
install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH)
|
||||
install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
@ -1,73 +0,0 @@
|
||||
========================================
|
||||
Using afl++ with partial instrumentation
|
||||
========================================
|
||||
|
||||
This file describes how you can selectively instrument only the source files
|
||||
that are interesting to you using the gcc instrumentation provided by
|
||||
afl++.
|
||||
|
||||
Plugin by hexcoder-.
|
||||
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
When building and testing complex programs where only a part of the program is
|
||||
the fuzzing target, it often helps to only instrument the necessary parts of
|
||||
the program, leaving the rest uninstrumented. This helps to focus the fuzzer
|
||||
on the important parts of the program, avoiding undesired noise and
|
||||
disturbance by uninteresting code being exercised.
|
||||
|
||||
For this purpose, I have added a "partial instrumentation" support to the gcc
|
||||
plugin of AFLFuzz that allows you to specify on a source file level which files
|
||||
should be compiled with or without instrumentation.
|
||||
|
||||
|
||||
## 2) Building the gcc plugin
|
||||
|
||||
The new code is part of the existing afl++ gcc plugin in the gcc_plugin/
|
||||
subdirectory. There is nothing specifically to do :)
|
||||
|
||||
|
||||
## 3) How to use the partial instrumentation mode
|
||||
|
||||
In order to build with partial instrumentation, you need to build with
|
||||
afl-gcc-fast and afl-g++-fast respectively. The only required change is
|
||||
that you need to set the environment variable AFL_GCC_INSTRUMENT_FILE when calling
|
||||
the compiler.
|
||||
|
||||
The environment variable must point to a file containing all the filenames
|
||||
that should be instrumented. For matching, the filename that is being compiled
|
||||
must end in the filename entry contained in this instrument list (to avoid breaking
|
||||
the matching when absolute paths are used during compilation).
|
||||
|
||||
For example if your source tree looks like this:
|
||||
|
||||
```
|
||||
project/
|
||||
project/feature_a/a1.cpp
|
||||
project/feature_a/a2.cpp
|
||||
project/feature_b/b1.cpp
|
||||
project/feature_b/b2.cpp
|
||||
```
|
||||
|
||||
and you only want to test feature_a, then create a instrument list file containing:
|
||||
|
||||
```
|
||||
feature_a/a1.cpp
|
||||
feature_a/a2.cpp
|
||||
```
|
||||
|
||||
However if the instrument list file contains only this, it works as well:
|
||||
|
||||
```
|
||||
a1.cpp
|
||||
a2.cpp
|
||||
```
|
||||
|
||||
but it might lead to files being unwantedly instrumented if the same filename
|
||||
exists somewhere else in the project directories.
|
||||
|
||||
The created instrument list file is then set to AFL_GCC_INSTRUMENT_FILE when you compile
|
||||
your program. For each file that didn't match the instrument list, the compiler will
|
||||
issue a warning at the end stating that no blocks were instrumented. If you
|
||||
didn't intend to instrument that file, then you can safely ignore that warning.
|
@ -1,406 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - GCC wrapper for GCC plugin
|
||||
------------------------------------------------
|
||||
|
||||
Written by Austin Seipp <aseipp@pobox.com> and
|
||||
Laszlo Szekeres <lszekeres@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
GCC integration design is based on the LLVM design, which comes
|
||||
from Laszlo Szekeres.
|
||||
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This program is a drop-in replacement for gcc, similar in most
|
||||
respects to ../afl-gcc, but with compiler instrumentation through a
|
||||
plugin. It tries to figure out compilation mode, adds a bunch of
|
||||
flags, and then calls the real compiler.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "common.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static u8 * obj_path; /* Path to runtime libraries */
|
||||
static u8 **cc_params; /* Parameters passed to the real CC */
|
||||
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
|
||||
u8 use_stdin = 0; /* dummy */
|
||||
|
||||
/* Try to find the runtime libraries. If that fails, abort. */
|
||||
|
||||
static void find_obj(u8 *argv0) {
|
||||
|
||||
u8 *afl_path = getenv("AFL_PATH");
|
||||
u8 *slash, *tmp;
|
||||
|
||||
if (afl_path) {
|
||||
|
||||
tmp = alloc_printf("%s/afl-gcc-rt.o", afl_path);
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = afl_path;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
}
|
||||
|
||||
slash = strrchr(argv0, '/');
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8 *dir;
|
||||
|
||||
*slash = 0;
|
||||
dir = ck_strdup(argv0);
|
||||
*slash = '/';
|
||||
|
||||
tmp = alloc_printf("%s/afl-gcc-rt.o", dir);
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = dir;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
ck_free(dir);
|
||||
|
||||
}
|
||||
|
||||
if (!access(AFL_PATH "/afl-gcc-rt.o", R_OK)) {
|
||||
|
||||
obj_path = AFL_PATH;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
FATAL(
|
||||
"Unable to find 'afl-gcc-rt.o' or 'afl-gcc-pass.so'. Please set "
|
||||
"AFL_PATH");
|
||||
|
||||
}
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char **argv) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1;
|
||||
u8 *name;
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
|
||||
|
||||
name = strrchr(argv[0], '/');
|
||||
if (!name)
|
||||
name = argv[0];
|
||||
else
|
||||
++name;
|
||||
|
||||
if (!strcmp(name, "afl-g++-fast")) {
|
||||
|
||||
u8 *alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
|
||||
|
||||
} else if (!strcmp(name, "afl-gcc-fast")) {
|
||||
|
||||
u8 *alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
|
||||
FATAL(
|
||||
"Name of the binary is not a known name, expected afl-(gcc|g++)-fast");
|
||||
|
||||
}
|
||||
|
||||
char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] = fplugin_arg;
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
|
||||
if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;
|
||||
|
||||
while (--argc) {
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
if (!strcmp(cur, "-m32")) FATAL("-m32 is not supported");
|
||||
#endif
|
||||
|
||||
if (!strcmp(cur, "-x")) x_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E") ||
|
||||
!strcmp(cur, "-v"))
|
||||
maybe_linking = 0;
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
|
||||
asan_set = 1;
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-shared")) maybe_linking = 0;
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_HARDEN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fstack-protector-all";
|
||||
|
||||
if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
|
||||
|
||||
}
|
||||
|
||||
if (!asan_set) {
|
||||
|
||||
if (getenv("AFL_USE_ASAN")) {
|
||||
|
||||
if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
if (getenv("AFL_HARDEN"))
|
||||
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=address";
|
||||
|
||||
} else if (getenv("AFL_USE_MSAN")) {
|
||||
|
||||
if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
if (getenv("AFL_HARDEN"))
|
||||
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=memory";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_USE_UBSAN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=undefined";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error";
|
||||
cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all";
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-g";
|
||||
cc_params[cc_par_cnt++] = "-O3";
|
||||
cc_params[cc_par_cnt++] = "-funroll-loops";
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_NO_BUILTIN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-bcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
|
||||
|
||||
}
|
||||
|
||||
#if defined(USEMMAP) && !defined(__HAIKU__)
|
||||
cc_params[cc_par_cnt++] = "-lrt";
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
|
||||
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
|
||||
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
|
||||
|
||||
/* When the user tries to use persistent or deferred forkserver modes by
|
||||
appending a single line to the program, we want to reliably inject a
|
||||
signature into the binary (to be picked up by afl-fuzz) and we want
|
||||
to call a function from the runtime .o file. This is unnecessarily
|
||||
painful for three reasons:
|
||||
|
||||
1) We need to convince the compiler not to optimize out the signature.
|
||||
This is done with __attribute__((used)).
|
||||
|
||||
2) We need to convince the linker, when called with -Wl,--gc-sections,
|
||||
not to do the same. This is done by forcing an assignment to a
|
||||
'volatile' pointer.
|
||||
|
||||
3) We need to declare __afl_persistent_loop() in the global namespace,
|
||||
but doing this within a method in a class is hard - :: and extern "C"
|
||||
are forbidden and __attribute__((alias(...))) doesn't work. Hence the
|
||||
__asm__ aliasing trick.
|
||||
|
||||
*/
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-D__AFL_LOOP(_A)="
|
||||
"({ static volatile char *_B __attribute__((used)); "
|
||||
" _B = (char*)\"" PERSIST_SIG
|
||||
"\"; "
|
||||
#ifdef __APPLE__
|
||||
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
|
||||
#else
|
||||
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
|
||||
#endif /* ^__APPLE__ */
|
||||
"_L(_A); })";
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-D__AFL_INIT()="
|
||||
"do { static volatile char *_A __attribute__((used)); "
|
||||
" _A = (char*)\"" DEFER_SIG
|
||||
"\"; "
|
||||
#ifdef __APPLE__
|
||||
"void _I(void) __asm__(\"___afl_manual_init\"); "
|
||||
#else
|
||||
"void _I(void) __asm__(\"__afl_manual_init\"); "
|
||||
#endif /* ^__APPLE__ */
|
||||
"_I(); } while (0)";
|
||||
|
||||
if (maybe_linking) {
|
||||
|
||||
if (x_set) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-x";
|
||||
cc_params[cc_par_cnt++] = "none";
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-gcc-rt.o", obj_path);
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
|
||||
|
||||
printf(cCYA
|
||||
"afl-gcc-fast" VERSION cRST
|
||||
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n"
|
||||
"\n"
|
||||
"afl-gcc-fast [options]\n"
|
||||
"\n"
|
||||
"This is a helper application for afl-fuzz. It serves as a drop-in "
|
||||
"replacement\n"
|
||||
"for gcc, letting you recompile third-party code with the required "
|
||||
"runtime\n"
|
||||
"instrumentation. A common use pattern would be one of the "
|
||||
"following:\n\n"
|
||||
|
||||
" CC=%s/afl-gcc-fast ./configure\n"
|
||||
" CXX=%s/afl-g++-fast ./configure\n\n"
|
||||
|
||||
"In contrast to the traditional afl-gcc tool, this version is "
|
||||
"implemented as\n"
|
||||
"a GCC plugin and tends to offer improved performance with slow "
|
||||
"programs\n"
|
||||
"(similarly to the LLVM plugin used by afl-clang-fast).\n\n"
|
||||
|
||||
"Environment variables used:\n"
|
||||
"AFL_CC: path to the C compiler to use\n"
|
||||
"AFL_CXX: path to the C++ compiler to use\n"
|
||||
"AFL_PATH: path to instrumenting pass and runtime (afl-gcc-rt.*o)\n"
|
||||
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_INST_RATIO: percentage of branches to instrument\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_DEBUG: enable developer debugging output\n"
|
||||
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_MSAN: activate memory sanitizer\n"
|
||||
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
|
||||
"AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
|
||||
"filename\n"
|
||||
|
||||
"\nafl-gcc-fast was built for gcc %s with the gcc binary path of "
|
||||
"\"%s\".\n\n",
|
||||
BIN_PATH, BIN_PATH, GCC_VERSION, GCC_BINDIR);
|
||||
|
||||
exit(1);
|
||||
|
||||
} else if ((isatty(2) && !getenv("AFL_QUIET")) ||
|
||||
|
||||
getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-gcc-fast" VERSION cRST
|
||||
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n");
|
||||
|
||||
if (getenv("AFL_GCC_INSTRUMENT_FILE") == NULL &&
|
||||
getenv("AFL_GCC_WHITELIST") == NULL) {
|
||||
|
||||
SAYF(
|
||||
cYEL
|
||||
"Warning:" cRST
|
||||
" using afl-gcc-fast without using AFL_GCC_INSTRUMENT_FILE currently "
|
||||
"produces worse results than afl-gcc. Even better, use "
|
||||
"llvm_mode for now.\n");
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
u8 *ptr;
|
||||
if (!be_quiet &&
|
||||
((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
|
||||
|
||||
u32 map_size = atoi(ptr);
|
||||
if (map_size != MAP_SIZE)
|
||||
WARNF("AFL_MAP_SIZE is not supported by afl-gcc-fast");
|
||||
|
||||
}
|
||||
|
||||
check_environment_vars(envp);
|
||||
|
||||
find_obj(argv[0]);
|
||||
|
||||
edit_params(argc, argv);
|
||||
/*if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
|
||||
printf("Calling \"%s\" with:\n", cc_params[0]);
|
||||
for(int i=1; i<cc_par_cnt; i++) printf("%s\n", cc_params[i]);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
|
||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1,315 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - GCC plugin instrumentation bootstrap
|
||||
---------------------------------------------------------
|
||||
|
||||
Written by Austin Seipp <aseipp@pobox.com> and
|
||||
Laszlo Szekeres <lszekeres@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
GCC integration design is based on the LLVM design, which comes
|
||||
from Laszlo Szekeres.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is the rewrite of afl-as.h's main_payload.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
#include "../config.h"
|
||||
#include "../types.h"
|
||||
|
||||
#ifdef USEMMAP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#ifndef USEMMAP
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Globals needed by the injected instrumentation. The __afl_area_initial region
|
||||
is used for instrumentation output before __afl_map_shm() has a chance to
|
||||
run. It will end up as .comm, so it shouldn't be too wasteful. */
|
||||
|
||||
u8 __afl_area_initial[MAP_SIZE];
|
||||
u8 *__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_prev_loc;
|
||||
u32 __afl_final_loc;
|
||||
#else
|
||||
__thread u32 __afl_prev_loc;
|
||||
__thread u32 __afl_final_loc;
|
||||
#endif
|
||||
|
||||
/* Trace a basic block with some ID */
|
||||
void __afl_trace(const u32 x) {
|
||||
|
||||
#if 1 /* enable for neverZero feature. */
|
||||
__afl_area_ptr[__afl_prev_loc ^ x] +=
|
||||
1 + ((u8)(1 + __afl_area_ptr[__afl_prev_loc ^ x]) == 0);
|
||||
#else
|
||||
++__afl_area_ptr[__afl_prev_loc ^ x];
|
||||
#endif
|
||||
|
||||
__afl_prev_loc = (x >> 1);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Running in persistent mode? */
|
||||
|
||||
static u8 is_persistent;
|
||||
|
||||
/* SHM setup. */
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
u8 *id_str = getenv(SHM_ENV_VAR);
|
||||
|
||||
/* If we're running under AFL, attach to the appropriate region, replacing the
|
||||
early-stage __afl_area_initial region that is needed to allow some really
|
||||
hacky .init code to work correctly in projects such as OpenSSL. */
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
unsigned char *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* map the shared memory segment to the address space of the process */
|
||||
shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
if (shm_base == MAP_FAILED) {
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
exit(2);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = shm_base;
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, NULL, 0);
|
||||
#endif
|
||||
|
||||
/* Whooooops. */
|
||||
|
||||
if (__afl_area_ptr == (void *)-1) exit(1);
|
||||
|
||||
/* Write something into the bitmap so that even with low AFL_INST_RATIO,
|
||||
our parent doesn't give up on us. */
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic. */
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 map_size = MAP_SIZE;
|
||||
s32 child_pid;
|
||||
|
||||
u8 child_stopped = 0;
|
||||
|
||||
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (MAP_SIZE <= 0x800000) {
|
||||
|
||||
map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
|
||||
memcpy(tmp, &map_size, 4);
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
|
||||
while (1) {
|
||||
|
||||
u32 was_killed;
|
||||
int status;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(1);
|
||||
|
||||
/* If we stopped the child in persistent mode, but there was a race
|
||||
condition and afl-fuzz already issued SIGKILL, write off the old
|
||||
process. */
|
||||
|
||||
if (child_stopped && was_killed) {
|
||||
|
||||
child_stopped = 0;
|
||||
if (waitpid(child_pid, &status, 0) < 0) exit(1);
|
||||
|
||||
}
|
||||
|
||||
if (!child_stopped) {
|
||||
|
||||
/* Once woken up, create a clone of our process. */
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) exit(1);
|
||||
|
||||
/* In child process: close fds, resume execution. */
|
||||
|
||||
if (!child_pid) {
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Special handling for persistent mode: if the child is alive but
|
||||
currently stopped, simply restart it with SIGCONT. */
|
||||
|
||||
kill(child_pid, SIGCONT);
|
||||
child_stopped = 0;
|
||||
|
||||
}
|
||||
|
||||
/* In parent process: write PID to pipe, then wait for child. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(1);
|
||||
|
||||
if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) exit(1);
|
||||
|
||||
/* In persistent mode, the child stops itself with SIGSTOP to indicate
|
||||
a successful run. In this case, we want to wake it up without forking
|
||||
again. */
|
||||
|
||||
if (WIFSTOPPED(status)) child_stopped = 1;
|
||||
|
||||
/* Relay wait status to pipe, then loop back. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* A simplified persistent mode handler, used as explained in README.md. */
|
||||
|
||||
int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
static u8 first_pass = 1;
|
||||
static u32 cycle_cnt;
|
||||
|
||||
if (first_pass) {
|
||||
|
||||
/* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.
|
||||
On subsequent calls, the parent will take care of that, but on the first
|
||||
iteration, it's our job to erase any trace of whatever happened
|
||||
before the loop. */
|
||||
|
||||
if (is_persistent) {
|
||||
|
||||
memset(__afl_area_ptr, 0, MAP_SIZE);
|
||||
__afl_area_ptr[0] = 1;
|
||||
__afl_prev_loc = 0;
|
||||
|
||||
}
|
||||
|
||||
cycle_cnt = max_cnt;
|
||||
first_pass = 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
if (is_persistent) {
|
||||
|
||||
if (--cycle_cnt) {
|
||||
|
||||
raise(SIGSTOP);
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
__afl_prev_loc = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
|
||||
/* When exiting __AFL_LOOP(), make sure that the subsequent code that
|
||||
follows the loop is not traced. We do that by pivoting back to the
|
||||
dummy output region. */
|
||||
|
||||
__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* This one can be called from user code when deferred forkserver mode
|
||||
is enabled. */
|
||||
|
||||
void __afl_manual_init(void) {
|
||||
|
||||
static u8 init_done;
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_map_shm();
|
||||
__afl_start_forkserver();
|
||||
init_done = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Proper initialization routine. */
|
||||
|
||||
__attribute__((constructor(101))) void __afl_auto_init(void) {
|
||||
|
||||
is_persistent = !!getenv(PERSIST_ENV_VAR);
|
||||
|
||||
if (getenv(DEFER_ENV_VAR)) return;
|
||||
|
||||
__afl_manual_init();
|
||||
|
||||
}
|
||||
|
@ -162,8 +162,7 @@ struct queue_entry {
|
||||
u8 *trace_mini; /* Trace bytes, if kept */
|
||||
u32 tc_ref; /* Trace bytes ref count */
|
||||
|
||||
struct queue_entry *next, /* Next element, if any */
|
||||
*next_100; /* 100 elements ahead */
|
||||
struct queue_entry *next; /* Next element, if any */
|
||||
|
||||
};
|
||||
|
||||
@ -575,8 +574,7 @@ typedef struct afl_state {
|
||||
|
||||
struct queue_entry *queue, /* Fuzzing queue (linked list) */
|
||||
*queue_cur, /* Current offset within the queue */
|
||||
*queue_top, /* Top of the list */
|
||||
*q_prev100; /* Previous 100 marker */
|
||||
*queue_top; /* Top of the list */
|
||||
|
||||
// growing buf
|
||||
struct queue_entry **queue_buf;
|
||||
@ -937,6 +935,7 @@ u8 has_new_bits(afl_state_t *, u8 *);
|
||||
|
||||
void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
|
||||
void load_extras(afl_state_t *, u8 *);
|
||||
void dedup_extras(afl_state_t *);
|
||||
void add_extra(afl_state_t *afl, u8 *mem, u32 len);
|
||||
void maybe_add_auto(afl_state_t *, u8 *, u32);
|
||||
void save_auto(afl_state_t *);
|
||||
@ -974,7 +973,7 @@ u8 fuzz_one(afl_state_t *);
|
||||
void bind_to_free_cpu(afl_state_t *);
|
||||
#endif
|
||||
void setup_post(afl_state_t *);
|
||||
void read_testcases(afl_state_t *);
|
||||
void read_testcases(afl_state_t *, u8 *);
|
||||
void perform_dry_run(afl_state_t *);
|
||||
void pivot_inputs(afl_state_t *);
|
||||
u32 find_start_position(afl_state_t *);
|
||||
|
@ -28,7 +28,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++2.68c"
|
||||
#define VERSION "++3.00a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -195,7 +195,7 @@
|
||||
steps; past this point, the "extras/user" step will be still carried out,
|
||||
but with proportionally lower odds: */
|
||||
|
||||
#define MAX_DET_EXTRAS 200
|
||||
#define MAX_DET_EXTRAS 256
|
||||
|
||||
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
|
||||
(first value), and to keep in memory as candidates. The latter should be much
|
||||
|
@ -69,6 +69,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_LLVM_CMPLOG",
|
||||
"AFL_LLVM_INSTRIM",
|
||||
"AFL_LLVM_CTX",
|
||||
"AFL_LLVM_DICT2FILE",
|
||||
"AFL_LLVM_DOCUMENT_IDS",
|
||||
"AFL_LLVM_INSTRUMENT",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
|
@ -30,7 +30,7 @@ cp ./program ./program.cmplog
|
||||
|
||||
## Use
|
||||
|
||||
AFL++ has the new -c option that can be used to specify a CmpLog binary (the second
|
||||
AFL++ has the new -c option that needs to be used to specify the CmpLog binary (the second
|
||||
build).
|
||||
|
||||
For example:
|
||||
@ -39,4 +39,4 @@ For example:
|
||||
afl-fuzz -i input -o output -c ./program.cmplog -m none -- ./program.afl @@
|
||||
```
|
||||
|
||||
Be careful to use -m none because CmpLog maps a lot of pages.
|
||||
Be sure to use `-m none` because CmpLog can map a lot of pages.
|
@ -4,7 +4,7 @@
|
||||
|
||||
This is an LLVM-based implementation of the context sensitive branch coverage.
|
||||
|
||||
Basically every function gets it's own ID and that ID is combined with the
|
||||
Basically every function gets its own ID and that ID is combined with the
|
||||
edges of the called functions.
|
||||
|
||||
So if both function A and function B call a function C, the coverage
|
@ -1,7 +1,7 @@
|
||||
# GCC-based instrumentation for afl-fuzz
|
||||
|
||||
(See [../README.md](../README.md) for the general instruction manual.)
|
||||
(See [../llvm_mode/README.md](../llvm_mode/README.md) for the LLVM-based instrumentation.)
|
||||
(See [README.llvm.md](README.llvm.md) for the LLVM-based instrumentation.)
|
||||
|
||||
!!! TODO items are:
|
||||
!!! => inline instrumentation has to work!
|
30
instrumentation/README.instrim.md
Normal file
30
instrumentation/README.instrim.md
Normal file
@ -0,0 +1,30 @@
|
||||
# InsTrim
|
||||
|
||||
InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing
|
||||
|
||||
## Introduction
|
||||
|
||||
InsTrim is the work of Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang.
|
||||
|
||||
It uses a CFG (call flow graph) and markers to instrument just what
|
||||
is necessary in the binary (ie less than llvm_mode). As a result the binary is
|
||||
about 10-15% faster compared to normal llvm_mode however with some coverage loss.
|
||||
It requires at least llvm version 3.8.0 to build.
|
||||
If you have LLVM 7+ we recommend PCGUARD instead.
|
||||
|
||||
## Usage
|
||||
|
||||
Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1`
|
||||
during compilation of the target.
|
||||
|
||||
There is also special mode which instruments loops in a way so that
|
||||
afl-fuzz can see which loop path has been selected but not being able to
|
||||
see how often the loop has been rerun.
|
||||
This again is a tradeoff for speed for less path information.
|
||||
To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
|
||||
|
||||
## Background
|
||||
|
||||
The paper from Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang:
|
||||
[InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]
|
||||
(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf)
|
@ -1,8 +1,8 @@
|
||||
# Using afl++ with partial instrumentation
|
||||
|
||||
This file describes how you can selectively instrument only the source files
|
||||
or functions that are interesting to you using the LLVM instrumentation
|
||||
provided by afl++
|
||||
This file describes how to selectively instrument only source files
|
||||
or functions that are of interest to you using the LLVM instrumentation
|
||||
provided by afl++.
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
@ -13,10 +13,10 @@ on the important parts of the program, avoiding undesired noise and
|
||||
disturbance by uninteresting code being exercised.
|
||||
|
||||
For this purpose, a "partial instrumentation" support en par with llvm sancov
|
||||
is provided by afl++ that allows you to specify on a source file and function
|
||||
is provided by afl++ that allows to specify on a source file and function
|
||||
level which function should be compiled with or without instrumentation.
|
||||
|
||||
Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead:
|
||||
Note: When using PCGUARD mode - and llvm 12+ - you can use this instead:
|
||||
https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
|
||||
|
||||
The llvm sancov list format is fully supported by afl++, however afl++ has
|
||||
@ -24,8 +24,8 @@ more flexibility.
|
||||
|
||||
## 2) Building the LLVM module
|
||||
|
||||
The new code is part of the existing afl++ LLVM module in the llvm_mode/
|
||||
subdirectory. There is nothing specifically to do :)
|
||||
The new code is part of the existing afl++ LLVM module in the instrumentation/
|
||||
subdirectory. There is nothing specifically to do for the build :)
|
||||
|
||||
## 3) How to use the partial instrumentation mode
|
||||
|
||||
@ -34,14 +34,14 @@ afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++.
|
||||
The only required change is that you need to set either the environment variable
|
||||
AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename.
|
||||
|
||||
That file then contains the filenames or functions that should be instrumented
|
||||
(AFL_LLVM_ALLOWLIST) or should specifically NOT be instrumented (AFL_LLVM_DENYLIST).
|
||||
That file should contain the file names or functions that are to be instrumented
|
||||
(AFL_LLVM_ALLOWLIST) or are specifically NOT to be instrumented (AFL_LLVM_DENYLIST).
|
||||
|
||||
For matching, the function/filename that is being compiled must end in the
|
||||
function/filename entry contained in this instrument file list (to avoid
|
||||
breaking the matching when absolute paths are used during compilation).
|
||||
For matching to succeed, the function/file name that is being compiled must end in the
|
||||
function/file name entry contained in this instrument file list. That is to avoid
|
||||
breaking the match when absolute paths are used during compilation.
|
||||
|
||||
**NOTE:** In builds with optimization enabled functions might be inlined and would not match!
|
||||
**NOTE:** In builds with optimization enabled, functions might be inlined and would not match!
|
||||
|
||||
For example if your source tree looks like this:
|
||||
```
|
||||
@ -52,13 +52,13 @@ project/feature_b/b1.cpp
|
||||
project/feature_b/b2.cpp
|
||||
```
|
||||
|
||||
and you only want to test feature_a, then create a instrument file list file containing:
|
||||
and you only want to test feature_a, then create an "instrument file list" file containing:
|
||||
```
|
||||
feature_a/a1.cpp
|
||||
feature_a/a2.cpp
|
||||
```
|
||||
|
||||
However if the instrument file list file contains only this, it works as well:
|
||||
However if the "instrument file list" file contains only this, it works as well:
|
||||
```
|
||||
a1.cpp
|
||||
a2.cpp
|
||||
@ -67,9 +67,9 @@ but it might lead to files being unwantedly instrumented if the same filename
|
||||
exists somewhere else in the project directories.
|
||||
|
||||
You can also specify function names. Note that for C++ the function names
|
||||
must be mangled to match!
|
||||
must be mangled to match! `nm` can print these names.
|
||||
|
||||
afl++ is able to identify if an entry is a filename or a function.
|
||||
afl++ is able to identify whether an entry is a filename or a function.
|
||||
However if you want to be sure (and compliant to the sancov allow/blocklist
|
||||
format), you can specify source file entries like this:
|
||||
```
|
||||
@ -82,5 +82,6 @@ fun: MallocFoo
|
||||
Note that whitespace is ignored and comments (`# foo`) are supported.
|
||||
|
||||
## 4) UNIX-style pattern matching
|
||||
You can add UNIX-style pattern matching in the the instrument file list entries.
|
||||
|
||||
You can add UNIX-style pattern matching in the "instrument file list" entries.
|
||||
See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
|
@ -1,5 +1,15 @@
|
||||
# laf-intel instrumentation
|
||||
|
||||
## Introduction
|
||||
|
||||
This originally is the work of an individual nicknamed laf-intel.
|
||||
His blog [Circumventing Fuzzing Roadblocks with Compiler Transformations]
|
||||
(https://lafintel.wordpress.com/) and gitlab repo [laf-llvm-pass]
|
||||
(https://gitlab.com/laf-intel/laf-llvm-pass/)
|
||||
describe some code transformations that
|
||||
help afl++ to enter conditional blocks, where conditions consist of
|
||||
comparisons of large values.
|
||||
|
||||
## Usage
|
||||
|
||||
By default these passes will not run when you compile programs using
|
||||
@ -24,18 +34,22 @@ Enables the split-compares pass.
|
||||
By default it will
|
||||
1. simplify operators >= (and <=) into chains of > (<) and == comparisons
|
||||
2. change signed integer comparisons to a chain of sign-only comparison
|
||||
and unsigned comparisons
|
||||
and unsigned integer comparisons
|
||||
3. split all unsigned integer comparisons with bit widths of
|
||||
64, 32 or 16 bits to chains of 8 bits comparisons.
|
||||
|
||||
You can change the behaviour of the last step by setting
|
||||
`export AFL_LLVM_LAF_SPLIT_COMPARES_BITW=<bit_width>`, where
|
||||
bit_width may be 64, 32 or 16.
|
||||
bit_width may be 64, 32 or 16. For example, a bit_width of 16
|
||||
would split larger comparisons down to 16 bit comparisons.
|
||||
|
||||
A new experimental feature is splitting floating point comparisons into a
|
||||
series of sign, exponent and mantissa comparisons followed by splitting each
|
||||
of them into 8 bit comparisons when necessary.
|
||||
It is activated with the `AFL_LLVM_LAF_SPLIT_FLOATS` setting.
|
||||
Please note that full IEEE 754 functionality is not preserved, that is
|
||||
values of nan and infinity will probably behave differently.
|
||||
|
||||
Note that setting this automatically activates `AFL_LLVM_LAF_SPLIT_COMPARES`
|
||||
|
||||
You can also set `AFL_LLVM_LAF_ALL` and have all of the above enabled :-)
|
@ -1,8 +1,8 @@
|
||||
# Fast LLVM-based instrumentation for afl-fuzz
|
||||
|
||||
(See [../README](../README.md) for the general instruction manual.)
|
||||
(See [../README.md](../README.md) for the general instruction manual.)
|
||||
|
||||
(See [../gcc_plugin/README](../gcc_plugin/README.md) for the GCC-based instrumentation.)
|
||||
(See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.)
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
@ -93,15 +93,16 @@ operating mode of AFL, e.g.:
|
||||
|
||||
Be sure to also include CXX set to afl-clang-fast++ for C++ code.
|
||||
|
||||
Note that afl-clang-fast/afl-clang-fast++ are just pointers to afl-cc.
|
||||
You can also use afl-cc/afl-c++ and instead direct it to use LLVM
|
||||
instrumentation by either setting `AFL_CC_COMPILER=LLVM` or pass the parameter
|
||||
`--afl-llvm` via CFLAGS/CXXFLAGS/CPPFLAGS.
|
||||
|
||||
The tool honors roughly the same environmental variables as afl-gcc (see
|
||||
[docs/env_variables.md](../docs/env_variables.md)). This includes AFL_USE_ASAN,
|
||||
AFL_HARDEN, and AFL_DONT_OPTIMIZE. However AFL_INST_RATIO is not honored
|
||||
as it does not serve a good purpose with the more effective instrim CFG
|
||||
analysis.
|
||||
|
||||
Note: if you want the LLVM helper to be installed on your system for all
|
||||
users, you need to build it before issuing 'make install' in the parent
|
||||
directory.
|
||||
as it does not serve a good purpose with the more effective PCGUARD, LTO and
|
||||
instrim CFG analysis.
|
||||
|
||||
## 3) Options
|
||||
|
||||
@ -109,9 +110,9 @@ Several options are present to make llvm_mode faster or help it rearrange
|
||||
the code to make afl-fuzz path discovery easier.
|
||||
|
||||
If you need just to instrument specific parts of the code, you can the instrument file list
|
||||
which C/C++ files to actually instrument. See [README.instrument_list](README.instrument_list.md)
|
||||
which C/C++ files to actually instrument. See [README.instrument_list.md](README.instrument_list.md)
|
||||
|
||||
For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md)
|
||||
For splitting memcmp, strncmp, etc. please see [README.laf-intel.md](README.laf-intel.md)
|
||||
|
||||
Then there are different ways of instrumenting the target:
|
||||
|
||||
@ -119,42 +120,42 @@ Then there are different ways of instrumenting the target:
|
||||
markers to just instrument what is needed. This increases speed by 10-15%
|
||||
without any disadvantages
|
||||
If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1
|
||||
See [README.instrim](README.instrim.md)
|
||||
See [README.instrim.md](README.instrim.md)
|
||||
|
||||
2. An even better instrumentation strategy uses LTO and link time
|
||||
instrumentation. Note that not all targets can compile in this mode, however
|
||||
if it works it is the best option you can use.
|
||||
Simply use afl-clang-lto/afl-clang-lto++ to use this option.
|
||||
See [README.lto](README.lto.md)
|
||||
See [README.lto.md](README.lto.md)
|
||||
|
||||
3. Alternativly you can choose a completely different coverage method:
|
||||
|
||||
3a. N-GRAM coverage - which combines the previous visited edges with the
|
||||
current one. This explodes the map but on the other hand has proven to be
|
||||
effective for fuzzing.
|
||||
See [README.ngram](README.ngram.md)
|
||||
See [README.ngram.md](README.ngram.md)
|
||||
|
||||
3b. Context sensitive coverage - which combines the visited edges with an
|
||||
individual caller ID (the function that called the current one)
|
||||
[README.ctx](README.ctx.md)
|
||||
[README.ctx.md](README.ctx.md)
|
||||
|
||||
Then - additionally to one of the instrumentation options above - there is
|
||||
a very effective new instrumentation option called CmpLog as an alternative to
|
||||
laf-intel that allow AFL++ to apply mutations similar to Redqueen.
|
||||
See [README.cmplog](README.cmplog.md)
|
||||
See [README.cmplog.md](README.cmplog.md)
|
||||
|
||||
Finally if your llvm version is 8 or lower, you can activate a mode that
|
||||
prevents that a counter overflow result in a 0 value. This is good for
|
||||
path discovery, but the llvm implementation for x86 for this functionality
|
||||
is not optimal and was only fixed in llvm 9.
|
||||
You can set this with AFL_LLVM_NOT_ZERO=1
|
||||
See [README.neverzero](README.neverzero.md)
|
||||
See [README.neverzero.md](README.neverzero.md)
|
||||
|
||||
## 4) Snapshot feature
|
||||
|
||||
To speed up fuzzing you can use a linux loadable kernel module which enables
|
||||
a snapshot feature.
|
||||
See [README.snapshot](README.snapshot.md)
|
||||
See [README.snapshot.md](README.snapshot.md)
|
||||
|
||||
## 5) Gotchas, feedback, bugs
|
||||
|
||||
@ -182,5 +183,12 @@ targets this way:
|
||||
AFL_LLVM_INSTRUMENT=PCGUARD make
|
||||
```
|
||||
|
||||
Note that this us currently the default, as it is the best mode.
|
||||
Note that this us currently the default if you use LLVM >= 7, as it is the best
|
||||
mode. Recommended is LLVM >= 9.
|
||||
If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode.
|
||||
|
||||
## 8) Bonus feature: 'dict2file' pass
|
||||
|
||||
Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation
|
||||
all constant string compare parameters will be written to this file to be
|
||||
used with afl-fuzz' `-x` option.
|
@ -95,10 +95,7 @@ export PATH=`pwd`/bin:$PATH
|
||||
export LLVM_CONFIG=`pwd`/bin/llvm-config
|
||||
cd /path/to/AFLplusplus/
|
||||
make
|
||||
cd llvm_mode
|
||||
make
|
||||
cd ..
|
||||
make install
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## How to use afl-clang-lto
|
||||
@ -115,18 +112,18 @@ make
|
||||
```
|
||||
|
||||
NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
|
||||
`afl-ld-lto` for this for `LD=` for `configure`.
|
||||
`afl-ld-lto` for `LD=` before `configure`.
|
||||
|
||||
## AUTODICTIONARY feature
|
||||
|
||||
While compiling, automatically a dictionary based on string comparisons is
|
||||
generated put into the target binary. This dictionary is transfered to afl-fuzz
|
||||
While compiling, a dictionary based on string comparisons is automatically
|
||||
generated and put into the target binary. This dictionary is transfered to afl-fuzz
|
||||
on start. This improves coverage statistically by 5-10% :)
|
||||
|
||||
## Fixed memory map
|
||||
|
||||
To speed up fuzzing, it is possible to set a fixed shared memory map.
|
||||
Recommened is the value 0x10000.
|
||||
Recommended is the value 0x10000.
|
||||
In most cases this will work without any problems. However if a target uses
|
||||
early constructors, ifuncs or a deferred forkserver this can crash the target.
|
||||
On unusual operating systems/processors/kernels or weird libraries this might
|
||||
@ -136,14 +133,14 @@ to be dynamic - the original afl way, which is slower).
|
||||
|
||||
## Document edge IDs
|
||||
|
||||
Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge
|
||||
Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document in a file which edge
|
||||
ID was given to which function. This helps to identify functions with variable
|
||||
bytes or which functions were touched by an input.
|
||||
|
||||
## Solving difficult targets
|
||||
|
||||
Some targets are difficult because the configure script does unusual stuff that
|
||||
is unexpected for afl. See the next chapter `Potential issues` how to solve
|
||||
is unexpected for afl. See the next chapter `Potential issues` for how to solve
|
||||
these.
|
||||
|
||||
### Example: ffmpeg
|
||||
@ -151,7 +148,7 @@ these.
|
||||
An example of a hard to solve target is ffmpeg. Here is how to successfully
|
||||
instrument it:
|
||||
|
||||
1. Get and extract the current ffmpeg and change to it's directory
|
||||
1. Get and extract the current ffmpeg and change to its directory
|
||||
|
||||
2. Running configure with --cc=clang fails and various other items will fail
|
||||
when compiling, so we have to trick configure:
|
||||
@ -221,13 +218,13 @@ If you see this message:
|
||||
/bin/ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one
|
||||
```
|
||||
This is because usually gnu gcc ranlib is being called which cannot deal with clang LTO files.
|
||||
The solution is simple: when you ./configure you have also have to set RANLIB=llvm-ranlib and AR=llvm-ar
|
||||
The solution is simple: when you ./configure you also have to set RANLIB=llvm-ranlib and AR=llvm-ar
|
||||
|
||||
Solution:
|
||||
```
|
||||
AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared
|
||||
```
|
||||
and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it.
|
||||
and on some targets you have to set AR=/RANLIB= even for make as the configure script does not save it.
|
||||
Other targets ignore environment variables and need the parameters set via
|
||||
`./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!).
|
||||
|
||||
@ -246,8 +243,8 @@ AS=llvm-as ...
|
||||
afl-clang-lto is still work in progress.
|
||||
|
||||
Known issues:
|
||||
* Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously
|
||||
* Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
|
||||
* Anything that llvm 11+ cannot compile, afl-clang-lto cannot compile either - obviously
|
||||
* Anything that does not compile with LTO, afl-clang-lto cannot compile either - obviously
|
||||
|
||||
Hence if building a target with afl-clang-lto fails try to build it with llvm12
|
||||
and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and
|
||||
@ -267,14 +264,14 @@ for this in the PassManager: EP_FullLinkTimeOptimizationLast
|
||||
("Fun" info - nobody knows what this is doing. And the developer who
|
||||
implemented this didn't respond to emails.)
|
||||
|
||||
In December came then the idea to implement this as a pass that is run via
|
||||
In December then came the idea to implement this as a pass that is run via
|
||||
the llvm "opt" program, which is performed via an own linker that afterwards
|
||||
calls the real linker.
|
||||
This was first implemented in January and work ... kinda.
|
||||
The LTO time instrumentation worked, however the "how" the basic blocks were
|
||||
The LTO time instrumentation worked, however "how" the basic blocks were
|
||||
instrumented was a problem, as reducing duplicates turned out to be very,
|
||||
very difficult with a program that has so many paths and therefore so many
|
||||
dependencies. At lot of strategies were implemented - and failed.
|
||||
dependencies. A lot of strategies were implemented - and failed.
|
||||
And then sat solvers were tried, but with over 10.000 variables that turned
|
||||
out to be a dead-end too.
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
## Usage
|
||||
|
||||
In larger, complex or reiterative programs the counters that collect the edge
|
||||
coverage can easily fill up and wrap around.
|
||||
In larger, complex or reiterative programs the byte sized counters that collect
|
||||
the edge coverage can easily fill up and wrap around.
|
||||
This is not that much of an issue - unless by chance it wraps just to a value
|
||||
of zero when the program execution ends.
|
||||
In this case afl-fuzz is not able to see that the edge has been accessed and
|
@ -4,11 +4,11 @@
|
||||
|
||||
The most effective way is to fuzz in persistent mode, as the speed can easily
|
||||
be x10 or x20 times faster without any disadvanges.
|
||||
*All professionel fuzzing is using this mode.*
|
||||
*All professional fuzzing is using this mode.*
|
||||
|
||||
This requires that the target can be called in a (or several) function(s),
|
||||
and that the state can be resetted so that multiple calls be be performed
|
||||
without memory leaking and former runs having no impact on following runs
|
||||
and that its state can be resetted so that multiple calls can be performed
|
||||
without resource leaks and former runs having no impact on following runs
|
||||
(this can be seen by the `stability` indicator in the `afl-fuzz` UI).
|
||||
|
||||
Examples can be found in [examples/persistent_mode](../examples/persistent_mode).
|
||||
@ -67,7 +67,7 @@ add this just after the includes:
|
||||
#endif
|
||||
```
|
||||
|
||||
## 3) deferred initialization
|
||||
## 3) Deferred initialization
|
||||
|
||||
AFL tries to optimize performance by executing the targeted binary just once,
|
||||
stopping it just before main(), and then cloning this "main" process to get
|
||||
@ -112,7 +112,7 @@ With the location selected, add this code in the appropriate spot:
|
||||
You don't need the #ifdef guards, but including them ensures that the program
|
||||
will keep working normally when compiled with a tool other than afl-clang-fast.
|
||||
|
||||
Finally, recompile the program with afl-clang-fast (afl-gcc or afl-clang will
|
||||
Finally, recompile the program with afl-clang-fast/lto (afl-gcc or afl-clang will
|
||||
*not* generate a deferred-initialization binary) - and you should be all set!
|
||||
|
||||
*NOTE:* In the code between `main` and `__AFL_INIT()` should not be any code
|
||||
@ -142,7 +142,7 @@ and just before `__AFL_INIT()`:
|
||||
__afl_area_ptr = NULL;
|
||||
```
|
||||
|
||||
## 4) persistent mode
|
||||
## 4) Persistent mode
|
||||
|
||||
Some libraries provide APIs that are stateless, or whose state can be reset in
|
||||
between processing different input files. When such a reset is performed, a
|
||||
@ -183,7 +183,7 @@ PS. Because there are task switches still involved, the mode isn't as fast as
|
||||
faster than the normal fork() model, and compared to in-process fuzzing,
|
||||
should be a lot more robust.
|
||||
|
||||
## 5) shared memory fuzzing
|
||||
## 5) Shared memory fuzzing
|
||||
|
||||
You can speed up the fuzzing process even more by receiving the fuzzing data
|
||||
via shared memory instead of stdin or files.
|
@ -1,7 +1,7 @@
|
||||
# AFL++ snapshot feature
|
||||
|
||||
Snapshotting is a feature that makes a snapshot from a process and then
|
||||
restores it's state, which is faster then forking it again.
|
||||
restores its state, which is faster then forking it again.
|
||||
|
||||
All targets compiled with llvm_mode are automatically enabled for the
|
||||
snapshot feature.
|
@ -1,11 +1,6 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM instrumentation bootstrap
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
LLVM integration design comes from Laszlo Szekeres.
|
||||
american fuzzy lop++ - instrumentation bootstrap
|
||||
------------------------------------------------
|
||||
|
||||
Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -16,7 +11,6 @@
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is the rewrite of afl-as.h's main_payload.
|
||||
|
||||
*/
|
||||
|
||||
@ -111,6 +105,22 @@ static u8 is_persistent;
|
||||
|
||||
static u8 _is_sancov;
|
||||
|
||||
/* Uninspired gcc plugin instrumentation */
|
||||
|
||||
void __afl_trace(const u32 x) {
|
||||
|
||||
#if 1 /* enable for neverZero feature. */
|
||||
__afl_area_ptr[__afl_prev_loc[0] ^ x] +=
|
||||
1 + ((u8)(1 + __afl_area_ptr[__afl_prev_loc[0] ^ x]) == 0);
|
||||
#else
|
||||
++__afl_area_ptr[__afl_prev_loc[0] ^ x];
|
||||
#endif
|
||||
|
||||
__afl_prev_loc[0] = (x >> 1);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Error reporting to forkserver controller */
|
||||
|
||||
void send_forkserver_error(int error) {
|
||||
@ -808,7 +818,7 @@ static void __afl_start_forkserver(void) {
|
||||
}
|
||||
|
||||
/* A simplified persistent mode handler, used as explained in
|
||||
* llvm_mode/README.md. */
|
||||
* README.llvm.md. */
|
||||
|
||||
int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
@ -958,7 +968,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) {
|
||||
|
||||
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
|
||||
It remains non-operational in the traditional, plugin-backed LLVM mode.
|
||||
For more info about 'trace-pc-guard', see llvm_mode/README.md.
|
||||
For more info about 'trace-pc-guard', see README.llvm.md.
|
||||
|
||||
The first function (__sanitizer_cov_trace_pc_guard) is called back on every
|
||||
edge (as opposed to every basic block). */
|
599
instrumentation/afl-llvm-dict2file.so.cc
Normal file
599
instrumentation/afl-llvm-dict2file.so.cc
Normal file
@ -0,0 +1,599 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM LTO instrumentation pass
|
||||
----------------------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de>
|
||||
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This library is plugged into LLVM when invoking clang through afl-clang-lto.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_LLVM_PASS
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/MemorySSAUpdater.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
#ifndef O_DSYNC
|
||||
#define O_DSYNC O_SYNC
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class AFLdict2filePass : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
AFLdict2filePass() : ModulePass(ID) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void dict2file(int fd, u8 *mem, u32 len) {
|
||||
|
||||
int i, j, binary = 0;
|
||||
char line[MAX_AUTO_EXTRA * 8], tmp[8];
|
||||
|
||||
strcpy(line, "\"");
|
||||
j = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (isprint(mem[i])) {
|
||||
|
||||
line[j++] = mem[i];
|
||||
|
||||
} else {
|
||||
|
||||
if (i + 1 != len || mem[i] != 0 || binary || len == 4 || len == 8) {
|
||||
|
||||
line[j] = 0;
|
||||
sprintf(tmp, "\\x%02x", (u8)mem[i]);
|
||||
strcat(line, tmp);
|
||||
j = strlen(line);
|
||||
|
||||
}
|
||||
|
||||
binary = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
line[j] = 0;
|
||||
strcat(line, "\"\n");
|
||||
if (write(fd, line, strlen(line)) <= 0)
|
||||
PFATAL("Could not write to dictionary file");
|
||||
fsync(fd);
|
||||
|
||||
if (!be_quiet) fprintf(stderr, "Found dictionary token: %s", line);
|
||||
|
||||
}
|
||||
|
||||
bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
DenseMap<Value *, std::string *> valueMap;
|
||||
char * ptr;
|
||||
int fd, found = 0;
|
||||
|
||||
/* Show a banner */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-dict2file" VERSION cRST
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
scanForDangerousFunctions(&M);
|
||||
|
||||
ptr = getenv("AFL_LLVM_DICT2FILE");
|
||||
|
||||
if (!ptr || *ptr != '/')
|
||||
FATAL("AFL_LLVM_DICT2FILE is not set to an absolute path: %s", ptr);
|
||||
|
||||
if ((fd = open(ptr, O_WRONLY | O_APPEND | O_CREAT | O_DSYNC, 0644)) < 0)
|
||||
PFATAL("Could not open/create %s.", ptr);
|
||||
|
||||
/* Instrument all the things! */
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
if (isIgnoreFunction(&F)) continue;
|
||||
|
||||
/* Some implementation notes.
|
||||
*
|
||||
* We try to handle 3 cases:
|
||||
* - memcmp("foo", arg, 3) <- literal string
|
||||
* - static char globalvar[] = "foo";
|
||||
* memcmp(globalvar, arg, 3) <- global variable
|
||||
* - char localvar[] = "foo";
|
||||
* memcmp(locallvar, arg, 3) <- local variable
|
||||
*
|
||||
* The local variable case is the hardest. We can only detect that
|
||||
* case if there is no reassignment or change in the variable.
|
||||
* And it might not work across llvm version.
|
||||
* What we do is hooking the initializer function for local variables
|
||||
* (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
|
||||
* variable. And if that variable is then used in a compare function
|
||||
* we use that noted string.
|
||||
* This seems not to work for tokens that have a size <= 4 :-(
|
||||
*
|
||||
* - if the compared length is smaller than the string length we
|
||||
* save the full string. This is likely better for fuzzing but
|
||||
* might be wrong in a few cases depending on optimizers
|
||||
*
|
||||
* - not using StringRef because there is a bug in the llvm 11
|
||||
* checkout I am using which sometimes points to wrong strings
|
||||
*
|
||||
* Over and out. Took me a full day. damn. mh/vh
|
||||
*/
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
CmpInst * cmpInst = nullptr;
|
||||
|
||||
if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
Value * op = cmpInst->getOperand(1);
|
||||
ConstantInt *ilen = dyn_cast<ConstantInt>(op);
|
||||
|
||||
if (ilen) {
|
||||
|
||||
u64 val2 = 0, val = ilen->getZExtValue();
|
||||
u32 len = 0;
|
||||
if (val > 0x10000 && val < 0xffffffff) len = 4;
|
||||
if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8;
|
||||
|
||||
if (len) {
|
||||
|
||||
auto c = cmpInst->getPredicate();
|
||||
|
||||
switch (c) {
|
||||
|
||||
case CmpInst::FCMP_OGT: // fall through
|
||||
case CmpInst::FCMP_OLE: // fall through
|
||||
case CmpInst::ICMP_SLE: // fall through
|
||||
case CmpInst::ICMP_SGT:
|
||||
|
||||
// signed comparison and it is a negative constant
|
||||
if ((len == 4 && (val & 80000000)) ||
|
||||
(len == 8 && (val & 8000000000000000))) {
|
||||
|
||||
if ((val & 0xffff) != 1) val2 = val - 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// fall through
|
||||
|
||||
case CmpInst::FCMP_UGT: // fall through
|
||||
case CmpInst::FCMP_ULE: // fall through
|
||||
case CmpInst::ICMP_UGT: // fall through
|
||||
case CmpInst::ICMP_ULE:
|
||||
if ((val & 0xffff) != 0xfffe) val2 = val + 1;
|
||||
break;
|
||||
|
||||
case CmpInst::FCMP_OLT: // fall through
|
||||
case CmpInst::FCMP_OGE: // fall through
|
||||
case CmpInst::ICMP_SLT: // fall through
|
||||
case CmpInst::ICMP_SGE:
|
||||
|
||||
// signed comparison and it is a negative constant
|
||||
if ((len == 4 && (val & 80000000)) ||
|
||||
(len == 8 && (val & 8000000000000000))) {
|
||||
|
||||
if ((val & 0xffff) != 1) val2 = val - 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// fall through
|
||||
|
||||
case CmpInst::FCMP_ULT: // fall through
|
||||
case CmpInst::FCMP_UGE: // fall through
|
||||
case CmpInst::ICMP_ULT: // fall through
|
||||
case CmpInst::ICMP_UGE:
|
||||
if ((val & 0xffff) != 1) val2 = val - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
val2 = 0;
|
||||
|
||||
}
|
||||
|
||||
dict2file(fd, (u8 *)&val, len);
|
||||
found++;
|
||||
if (val2) {
|
||||
|
||||
dict2file(fd, (u8 *)&val2, len);
|
||||
found++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
bool isStrcmp = true;
|
||||
bool isMemcmp = true;
|
||||
bool isStrncmp = true;
|
||||
bool isStrcasecmp = true;
|
||||
bool isStrncasecmp = true;
|
||||
bool isIntMemcpy = true;
|
||||
bool addedNull = false;
|
||||
size_t optLen = 0;
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
|
||||
std::string FuncName = Callee->getName().str();
|
||||
isStrcmp &= !FuncName.compare("strcmp");
|
||||
isMemcmp &= !FuncName.compare("memcmp");
|
||||
isStrncmp &= !FuncName.compare("strncmp");
|
||||
isStrcasecmp &= !FuncName.compare("strcasecmp");
|
||||
isStrncasecmp &= !FuncName.compare("strncasecmp");
|
||||
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
|
||||
|
||||
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
|
||||
!isStrncasecmp && !isIntMemcpy)
|
||||
continue;
|
||||
|
||||
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
|
||||
* prototype */
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
|
||||
isStrcmp &=
|
||||
FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
|
||||
isStrcasecmp &=
|
||||
FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
|
||||
isMemcmp &= FT->getNumParams() == 3 &&
|
||||
FT->getReturnType()->isIntegerTy(32) &&
|
||||
FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy() &&
|
||||
FT->getParamType(2)->isIntegerTy();
|
||||
isStrncmp &= FT->getNumParams() == 3 &&
|
||||
FT->getReturnType()->isIntegerTy(32) &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0) ==
|
||||
IntegerType::getInt8PtrTy(M.getContext()) &&
|
||||
FT->getParamType(2)->isIntegerTy();
|
||||
isStrncasecmp &= FT->getNumParams() == 3 &&
|
||||
FT->getReturnType()->isIntegerTy(32) &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0) ==
|
||||
IntegerType::getInt8PtrTy(M.getContext()) &&
|
||||
FT->getParamType(2)->isIntegerTy();
|
||||
|
||||
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
|
||||
!isStrncasecmp && !isIntMemcpy)
|
||||
continue;
|
||||
|
||||
/* is a str{n,}{case,}cmp/memcmp, check if we have
|
||||
* str{case,}cmp(x, "const") or str{case,}cmp("const", x)
|
||||
* strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
|
||||
* memcmp(x, "const", ..) or memcmp("const", x, ..) */
|
||||
Value *Str1P = callInst->getArgOperand(0),
|
||||
*Str2P = callInst->getArgOperand(1);
|
||||
std::string Str1, Str2;
|
||||
StringRef TmpStr;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr1 = false;
|
||||
|
||||
} else {
|
||||
|
||||
HasStr1 = true;
|
||||
Str1 = TmpStr.str();
|
||||
|
||||
}
|
||||
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr2 = false;
|
||||
|
||||
} else {
|
||||
|
||||
HasStr2 = true;
|
||||
Str2 = TmpStr.str();
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
|
||||
FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
|
||||
Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
|
||||
Str2P->getName().str().c_str(), Str2.c_str(),
|
||||
HasStr2 == true ? "true" : "false");
|
||||
|
||||
// we handle the 2nd parameter first because of llvm memcpy
|
||||
if (!HasStr2) {
|
||||
|
||||
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
|
||||
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
|
||||
|
||||
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
|
||||
|
||||
if (Var->hasInitializer()) {
|
||||
|
||||
if (auto *Array =
|
||||
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
|
||||
|
||||
HasStr2 = true;
|
||||
Str2 = Array->getAsString().str();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for the internal memcpy routine we only care for the second
|
||||
// parameter and are not reporting anything.
|
||||
if (isIntMemcpy == true) {
|
||||
|
||||
if (HasStr2 == true) {
|
||||
|
||||
Value * op2 = callInst->getArgOperand(2);
|
||||
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
|
||||
if (ilen) {
|
||||
|
||||
uint64_t literalLength = Str2.size();
|
||||
uint64_t optLength = ilen->getZExtValue();
|
||||
if (literalLength + 1 == optLength) {
|
||||
|
||||
Str2.append("\0", 1); // add null byte
|
||||
addedNull = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
valueMap[Str1P] = new std::string(Str2);
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// Neither a literal nor a global variable?
|
||||
// maybe it is a local variable that we saved
|
||||
if (!HasStr2) {
|
||||
|
||||
std::string *strng = valueMap[Str2P];
|
||||
if (strng && !strng->empty()) {
|
||||
|
||||
Str2 = *strng;
|
||||
HasStr2 = true;
|
||||
if (debug)
|
||||
fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(), Str2P);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!HasStr1) {
|
||||
|
||||
auto Ptr = dyn_cast<ConstantExpr>(Str1P);
|
||||
|
||||
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
|
||||
|
||||
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
|
||||
|
||||
if (Var->hasInitializer()) {
|
||||
|
||||
if (auto *Array =
|
||||
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
|
||||
|
||||
HasStr1 = true;
|
||||
Str1 = Array->getAsString().str();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Neither a literal nor a global variable?
|
||||
// maybe it is a local variable that we saved
|
||||
if (!HasStr1) {
|
||||
|
||||
std::string *strng = valueMap[Str1P];
|
||||
if (strng && !strng->empty()) {
|
||||
|
||||
Str1 = *strng;
|
||||
HasStr1 = true;
|
||||
if (debug)
|
||||
fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(), Str1P);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* handle cases of one string is const, one string is variable */
|
||||
if (!(HasStr1 ^ HasStr2)) continue;
|
||||
|
||||
std::string thestring;
|
||||
|
||||
if (HasStr1)
|
||||
thestring = Str1;
|
||||
else
|
||||
thestring = Str2;
|
||||
|
||||
optLen = thestring.length();
|
||||
|
||||
if (isMemcmp || isStrncmp || isStrncasecmp) {
|
||||
|
||||
Value * op2 = callInst->getArgOperand(2);
|
||||
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
|
||||
if (ilen) {
|
||||
|
||||
uint64_t literalLength = optLen;
|
||||
optLen = ilen->getZExtValue();
|
||||
if (literalLength + 1 == optLen) { // add null byte
|
||||
thestring.append("\0", 1);
|
||||
addedNull = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// add null byte if this is a string compare function and a null
|
||||
// was not already added
|
||||
if (!isMemcmp) {
|
||||
|
||||
if (addedNull == false) {
|
||||
|
||||
thestring.append("\0", 1); // add null byte
|
||||
optLen++;
|
||||
|
||||
}
|
||||
|
||||
// ensure we do not have garbage
|
||||
size_t offset = thestring.find('\0', 0);
|
||||
if (offset + 1 < optLen) optLen = offset + 1;
|
||||
thestring = thestring.substr(0, optLen);
|
||||
|
||||
}
|
||||
|
||||
// we take the longer string, even if the compare was to a
|
||||
// shorter part. Note that depending on the optimizer of the
|
||||
// compiler this can be wrong, but it is more likely that this
|
||||
// is helping the fuzzer
|
||||
if (optLen != thestring.length()) optLen = thestring.length();
|
||||
if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
|
||||
if (optLen < 3) // too short? skip
|
||||
continue;
|
||||
|
||||
ptr = (char *)thestring.c_str();
|
||||
|
||||
dict2file(fd, (u8 *)ptr, optLen);
|
||||
found++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Say something nice. */
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
if (!found)
|
||||
OKF("No entries for a dictionary found.");
|
||||
else
|
||||
OKF("Wrote %d entries to the dictionary file.\n", found);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
char AFLdict2filePass::ID = 0;
|
||||
|
||||
static void registerAFLdict2filePass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLdict2filePass());
|
||||
|
||||
}
|
||||
|
||||
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
|
||||
"afl++ dict2file instrumentation pass",
|
||||
false, false);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass);
|
||||
|
@ -1,2 +0,0 @@
|
||||
all:
|
||||
@gmake all || echo please install GNUmake
|
@ -1,25 +0,0 @@
|
||||
# InsTrim
|
||||
|
||||
InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing
|
||||
|
||||
## Introduction
|
||||
|
||||
InsTrim uses CFG and markers to instrument just what is necessary in the
|
||||
binary in llvm_mode. It is about 10-15% faster without disadvantages.
|
||||
It requires at least llvm version 3.8.0.
|
||||
|
||||
## Usage
|
||||
|
||||
Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1`
|
||||
during compilation of the target.
|
||||
|
||||
There is also an advanced mode which instruments loops in a way so that
|
||||
afl-fuzz can see which loop path has been selected but not being able to
|
||||
see how often the loop has been rerun.
|
||||
This again is a tradeoff for speed for less path information.
|
||||
To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
|
||||
|
||||
## Background
|
||||
|
||||
The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]
|
||||
(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf)
|
File diff suppressed because it is too large
Load Diff
@ -466,7 +466,7 @@ void afl_forkserver(CPUState *cpu) {
|
||||
}
|
||||
|
||||
/* A simplified persistent mode handler, used as explained in
|
||||
* llvm_mode/README.md. */
|
||||
* instrumentation/README.llvm.md */
|
||||
|
||||
void afl_persistent_loop(void) {
|
||||
|
||||
|
1544
src/afl-cc.c
Normal file
1544
src/afl-cc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -101,7 +101,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
|
||||
|
||||
if (rptr < lptr || *rptr != '"') {
|
||||
|
||||
FATAL("Malformed name=\"value\" pair in line %u.", cur_line);
|
||||
WARNF("Malformed name=\"value\" pair in line %u.", cur_line);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
@ -141,13 +142,19 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
|
||||
|
||||
if (*lptr != '"') {
|
||||
|
||||
FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line);
|
||||
WARNF("Malformed name=\"keyword\" pair in line %u.", cur_line);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
++lptr;
|
||||
|
||||
if (!*lptr) { FATAL("Empty keyword in line %u.", cur_line); }
|
||||
if (!*lptr) {
|
||||
|
||||
WARNF("Empty keyword in line %u.", cur_line);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* Okay, let's allocate memory and copy data between "...", handling
|
||||
\xNN escaping, \\, and \". */
|
||||
@ -169,7 +176,9 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
|
||||
|
||||
case 1 ... 31:
|
||||
case 128 ... 255:
|
||||
FATAL("Non-printable characters in line %u.", cur_line);
|
||||
WARNF("Non-printable characters in line %u.", cur_line);
|
||||
continue;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
|
||||
@ -185,7 +194,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
|
||||
|
||||
if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) {
|
||||
|
||||
FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line);
|
||||
WARNF("Invalid escaping (not \\xNN) in line %u.", cur_line);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
@ -209,10 +219,11 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
|
||||
|
||||
if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE) {
|
||||
|
||||
FATAL(
|
||||
WARNF(
|
||||
"Keyword too big in line %u (%s, limit is %s)", cur_line,
|
||||
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), klen),
|
||||
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
@ -232,14 +243,19 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len,
|
||||
|
||||
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
|
||||
if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); }
|
||||
if (!afl->extras_cnt) {
|
||||
|
||||
WARNF("No usable data in '%s'", dir);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
|
||||
compare_extras_len);
|
||||
|
||||
OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt,
|
||||
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
|
||||
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
|
||||
ACTF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt,
|
||||
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
|
||||
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
|
||||
|
||||
if (max_len > 32) {
|
||||
|
||||
@ -250,8 +266,8 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len,
|
||||
|
||||
if (afl->extras_cnt > afl->max_det_extras) {
|
||||
|
||||
OKF("More than %d tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
WARNF("More than %d tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
|
||||
}
|
||||
|
||||
@ -320,9 +336,10 @@ void load_extras(afl_state_t *afl, u8 *dir) {
|
||||
if (st.st_size > MAX_DICT_FILE) {
|
||||
|
||||
WARNF(
|
||||
"Extra '%s' is very big (%s, limit is %s)", fn,
|
||||
"Extra '%s' is too big (%s, limit is %s)", fn,
|
||||
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size),
|
||||
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
@ -370,16 +387,74 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
/* Adds a new extra / dict entry. Used for LTO autodict. */
|
||||
/* Removes duplicates from the loaded extras. This can happen if multiple files
|
||||
are loaded */
|
||||
|
||||
void dedup_extras(afl_state_t *afl) {
|
||||
|
||||
if (afl->extras_cnt < 2) return;
|
||||
|
||||
u32 i, j, orig_cnt = afl->extras_cnt;
|
||||
|
||||
for (i = 0; i < afl->extras_cnt - 1; i++) {
|
||||
|
||||
for (j = i + 1; j < afl->extras_cnt; j++) {
|
||||
|
||||
restart_dedup:
|
||||
|
||||
// if the goto was used we could be at the end of the list
|
||||
if (j >= afl->extras_cnt || afl->extras[i].len != afl->extras[j].len)
|
||||
break;
|
||||
|
||||
if (memcmp(afl->extras[i].data, afl->extras[j].data,
|
||||
afl->extras[i].len) == 0) {
|
||||
|
||||
ck_free(afl->extras[j].data);
|
||||
if (j + 1 < afl->extras_cnt) // not at the end of the list?
|
||||
memmove((char *)&afl->extras[j], (char *)&afl->extras[j + 1],
|
||||
(afl->extras_cnt - j - 1) * sizeof(struct extra_data));
|
||||
afl->extras_cnt--;
|
||||
goto restart_dedup; // restart if several duplicates are in a row
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (afl->extras_cnt != orig_cnt)
|
||||
afl->extras = afl_realloc((void **)&afl->extras,
|
||||
afl->extras_cnt * sizeof(struct extra_data));
|
||||
|
||||
}
|
||||
|
||||
/* Adds a new extra / dict entry. */
|
||||
void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
u32 i, found = 0;
|
||||
|
||||
for (i = 0; i < afl->extras_cnt; i++) {
|
||||
|
||||
if (afl->extras[i].len == len) {
|
||||
|
||||
if (memcmp(afl->extras[i].data, mem, len) == 0) return;
|
||||
found = 1;
|
||||
|
||||
} else {
|
||||
|
||||
if (found) break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (len > MAX_DICT_FILE) {
|
||||
|
||||
WARNF("Extra '%.*s' is very big (%s, limit is %s)", (int)len, mem,
|
||||
WARNF("Extra '%.*s' is too big (%s, limit is %s)", (int)len, mem,
|
||||
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len),
|
||||
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
|
||||
return;
|
||||
|
||||
} else if (len > 32) {
|
||||
|
||||
@ -405,8 +480,8 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
if (afl->extras_cnt == afl->max_det_extras + 1) {
|
||||
|
||||
OKF("More than %d tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
WARNF("More than %d tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
|
||||
}
|
||||
|
||||
@ -609,7 +684,7 @@ void load_auto(afl_state_t *afl) {
|
||||
|
||||
} else {
|
||||
|
||||
OKF("No auto-generated dictionary tokens to reuse.");
|
||||
ACTF("No auto-generated dictionary tokens to reuse.");
|
||||
|
||||
}
|
||||
|
||||
|
@ -611,37 +611,43 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
/* Read all testcases from the input directory, then queue them for testing.
|
||||
Called at startup. */
|
||||
|
||||
void read_testcases(afl_state_t *afl) {
|
||||
void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
|
||||
struct dirent **nl;
|
||||
s32 nl_cnt;
|
||||
s32 nl_cnt, subdirs = 1;
|
||||
u32 i;
|
||||
u8 * fn1;
|
||||
|
||||
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
u8 * fn1, *dir = directory;
|
||||
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
|
||||
/* Auto-detect non-in-place resumption attempts. */
|
||||
|
||||
fn1 = alloc_printf("%s/queue", afl->in_dir);
|
||||
if (!access(fn1, F_OK)) {
|
||||
if (dir == NULL) {
|
||||
|
||||
afl->in_dir = fn1;
|
||||
fn1 = alloc_printf("%s/queue", afl->in_dir);
|
||||
if (!access(fn1, F_OK)) {
|
||||
|
||||
} else {
|
||||
afl->in_dir = fn1;
|
||||
subdirs = 0;
|
||||
|
||||
ck_free(fn1);
|
||||
} else {
|
||||
|
||||
ck_free(fn1);
|
||||
|
||||
}
|
||||
|
||||
dir = afl->in_dir;
|
||||
|
||||
}
|
||||
|
||||
ACTF("Scanning '%s'...", afl->in_dir);
|
||||
ACTF("Scanning '%s'...", dir);
|
||||
|
||||
/* We use scandir() + alphasort() rather than readdir() because otherwise,
|
||||
the ordering of test cases would vary somewhat randomly and would be
|
||||
difficult to control. */
|
||||
|
||||
nl_cnt = scandir(afl->in_dir, &nl, NULL, alphasort);
|
||||
nl_cnt = scandir(dir, &nl, NULL, alphasort);
|
||||
|
||||
if (nl_cnt < 0) {
|
||||
if (nl_cnt < 0 && directory == NULL) {
|
||||
|
||||
if (errno == ENOENT || errno == ENOTDIR) {
|
||||
|
||||
@ -656,7 +662,7 @@ void read_testcases(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
PFATAL("Unable to open '%s'", afl->in_dir);
|
||||
PFATAL("Unable to open '%s'", dir);
|
||||
|
||||
}
|
||||
|
||||
@ -674,19 +680,29 @@ void read_testcases(afl_state_t *afl) {
|
||||
u8 dfn[PATH_MAX];
|
||||
snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
|
||||
nl[i]->d_name);
|
||||
u8 *fn2 = alloc_printf("%s/%s", afl->in_dir, nl[i]->d_name);
|
||||
u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
|
||||
|
||||
u8 passed_det = 0;
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
|
||||
if (lstat(fn2, &st) || access(fn2, R_OK)) {
|
||||
|
||||
PFATAL("Unable to access '%s'", fn2);
|
||||
|
||||
}
|
||||
|
||||
/* This also takes care of . and .. */
|
||||
/* obviously we want to skip "descending" into . and .. directories,
|
||||
however it is a good idea to skip also directories that start with
|
||||
a dot */
|
||||
if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
read_testcases(afl, fn2);
|
||||
ck_free(fn2);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
free(nl[i]);
|
||||
|
||||
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
|
||||
|
||||
@ -718,7 +734,7 @@ void read_testcases(afl_state_t *afl) {
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
if (!afl->queued_paths) {
|
||||
if (!afl->queued_paths && directory == NULL) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Looks like there are no valid test cases in the input directory! The "
|
||||
@ -985,6 +1001,76 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
/* Now we remove all entries from the queue that have a duplicate trace map */
|
||||
|
||||
q = afl->queue;
|
||||
struct queue_entry *p, *prev = NULL;
|
||||
int duplicates = 0;
|
||||
|
||||
restart_outer_cull_loop:
|
||||
|
||||
while (q) {
|
||||
|
||||
if (q->cal_failed || !q->exec_cksum) continue;
|
||||
|
||||
restart_inner_cull_loop:
|
||||
|
||||
p = q->next;
|
||||
|
||||
while (p) {
|
||||
|
||||
if (!p->cal_failed && p->exec_cksum == q->exec_cksum) {
|
||||
|
||||
duplicates = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
|
||||
// We do not remove any of the memory allocated because for
|
||||
// splicing the data might still be interesting.
|
||||
// We only decouple them from the linked list.
|
||||
// This will result in some leaks at exit, but who cares.
|
||||
|
||||
// we keep the shorter file
|
||||
if (p->len >= q->len) {
|
||||
|
||||
q->next = p->next;
|
||||
goto restart_inner_cull_loop;
|
||||
|
||||
} else {
|
||||
|
||||
if (prev)
|
||||
prev->next = q = p;
|
||||
else
|
||||
afl->queue = q = p;
|
||||
goto restart_outer_cull_loop;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
|
||||
}
|
||||
|
||||
prev = q;
|
||||
q = q->next;
|
||||
|
||||
}
|
||||
|
||||
if (duplicates) {
|
||||
|
||||
afl->max_depth = 0;
|
||||
q = afl->queue;
|
||||
while (q) {
|
||||
|
||||
if (q->depth > afl->max_depth) afl->max_depth = q->depth;
|
||||
q = q->next;
|
||||
|
||||
}
|
||||
|
||||
afl->queue = afl->queue_top = afl->queue;
|
||||
|
||||
}
|
||||
|
||||
OKF("All test cases processed.");
|
||||
|
||||
}
|
||||
|
@ -1707,20 +1707,8 @@ custom_mutator_stage:
|
||||
|
||||
} while (tid == afl->current_entry && afl->queued_paths > 1);
|
||||
|
||||
target = afl->queue;
|
||||
|
||||
while (tid >= 100) {
|
||||
|
||||
target = target->next_100;
|
||||
tid -= 100;
|
||||
|
||||
}
|
||||
|
||||
while (tid--) {
|
||||
|
||||
target = target->next;
|
||||
|
||||
}
|
||||
afl->splicing_with = tid;
|
||||
target = afl->queue_buf[tid];
|
||||
|
||||
/* Make sure that the target has a reasonable length. */
|
||||
|
||||
@ -4518,20 +4506,7 @@ pacemaker_fuzzing:
|
||||
} while (tid == afl->current_entry);
|
||||
|
||||
afl->splicing_with = tid;
|
||||
target = afl->queue;
|
||||
|
||||
while (tid >= 100) {
|
||||
|
||||
target = target->next_100;
|
||||
tid -= 100;
|
||||
|
||||
}
|
||||
|
||||
while (tid--) {
|
||||
|
||||
target = target->next;
|
||||
|
||||
}
|
||||
target = afl->queue_buf[tid];
|
||||
|
||||
/* Make sure that the target has a reasonable length. */
|
||||
|
||||
|
@ -230,7 +230,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
} else {
|
||||
|
||||
afl->q_prev100 = afl->queue = afl->queue_top = q;
|
||||
afl->queue = afl->queue_top = q;
|
||||
|
||||
}
|
||||
|
||||
@ -239,13 +239,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
afl->cycles_wo_finds = 0;
|
||||
|
||||
if (!(afl->queued_paths % 100)) {
|
||||
|
||||
afl->q_prev100->next_100 = q;
|
||||
afl->q_prev100 = q;
|
||||
|
||||
}
|
||||
|
||||
struct queue_entry **queue_buf = afl_realloc(
|
||||
AFL_BUF_PARAM(queue), afl->queued_paths * sizeof(struct queue_entry *));
|
||||
if (unlikely(!queue_buf)) { PFATAL("alloc"); }
|
||||
@ -281,15 +274,15 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
void destroy_queue(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q = afl->queue, *n;
|
||||
struct queue_entry *q;
|
||||
u32 i;
|
||||
|
||||
while (q) {
|
||||
for (i = 0; i < afl->queued_paths; i++) {
|
||||
|
||||
n = q->next;
|
||||
q = afl->queue_buf[i];
|
||||
ck_free(q->fname);
|
||||
ck_free(q->trace_mini);
|
||||
ck_free(q);
|
||||
q = n;
|
||||
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,12 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
|
||||
u8 fn[PATH_MAX];
|
||||
snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
|
||||
FILE *f = create_ffile(fn);
|
||||
u32 i;
|
||||
u32 i;
|
||||
|
||||
fprintf(f, "# environment variables:\n");
|
||||
u32 s_afl_env = (u32)
|
||||
sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) -
|
||||
1U;
|
||||
u32 s_afl_env = (u32)sizeof(afl_environment_variables) /
|
||||
sizeof(afl_environment_variables[0]) -
|
||||
1U;
|
||||
|
||||
for (i = 0; i < s_afl_env; ++i) {
|
||||
|
||||
@ -75,6 +75,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
|
||||
fclose(f);
|
||||
@ -982,10 +983,9 @@ void show_stats(afl_state_t *afl) {
|
||||
void show_init_stats(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q = afl->queue;
|
||||
u32 min_bits = 0, max_bits = 0;
|
||||
u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0;
|
||||
u64 min_us = 0, max_us = 0;
|
||||
u64 avg_us = 0;
|
||||
u32 max_len = 0;
|
||||
|
||||
u8 val_bufs[4][STRINGIFY_VAL_SIZE_MAX];
|
||||
#define IB(i) val_bufs[(i)], sizeof(val_bufs[(i)])
|
||||
@ -1006,6 +1006,7 @@ void show_init_stats(afl_state_t *afl) {
|
||||
|
||||
if (q->len > max_len) { max_len = q->len; }
|
||||
|
||||
++count;
|
||||
q = q->next;
|
||||
|
||||
}
|
||||
@ -1072,11 +1073,12 @@ void show_init_stats(afl_state_t *afl) {
|
||||
OKF("Here are some useful stats:\n\n"
|
||||
|
||||
cGRA " Test case count : " cRST
|
||||
"%u favored, %u variable, %u total\n" cGRA " Bitmap range : " cRST
|
||||
"%u favored, %u variable, %u ignored, %u total\n" cGRA
|
||||
" Bitmap range : " cRST
|
||||
"%u to %u bits (average: %0.02f bits)\n" cGRA
|
||||
" Exec timing : " cRST "%s to %s us (average: %s us)\n",
|
||||
afl->queued_favored, afl->queued_variable, afl->queued_paths, min_bits,
|
||||
max_bits,
|
||||
afl->queued_favored, afl->queued_variable, afl->queued_paths - count,
|
||||
afl->queued_paths, min_bits, max_bits,
|
||||
((double)afl->total_bitmap_size) /
|
||||
(afl->total_bitmap_entries ? afl->total_bitmap_entries : 1),
|
||||
stringify_int(IB(0), min_us), stringify_int(IB(1), max_us),
|
||||
|
@ -119,8 +119,8 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"etc.)\n"
|
||||
" -d - quick & dirty mode (skips deterministic steps)\n"
|
||||
" -n - fuzz without instrumentation (non-instrumented mode)\n"
|
||||
" -x dict_file - optional fuzzer dictionary (see README.md, its really "
|
||||
"good!)\n\n"
|
||||
" -x dict_file - fuzzer dictionary (see README.md, specify up to 4 "
|
||||
"times)\n\n"
|
||||
|
||||
"Testing settings:\n"
|
||||
" -s seed - use a fixed seed for the RNG\n"
|
||||
@ -243,11 +243,11 @@ static int stricmp(char const *a, char const *b) {
|
||||
|
||||
int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
s32 opt;
|
||||
s32 opt, i;
|
||||
u64 prev_queued = 0;
|
||||
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
|
||||
u8 * extras_dir = 0;
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0;
|
||||
u8 * extras_dir[4];
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0;
|
||||
char **use_argv;
|
||||
|
||||
struct timeval tv;
|
||||
@ -450,8 +450,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 'x': /* dictionary */
|
||||
|
||||
if (extras_dir) { FATAL("Multiple -x options not supported"); }
|
||||
extras_dir = optarg;
|
||||
if (extras_dir_cnt >= 4) {
|
||||
|
||||
FATAL("More than four -x options are not supported");
|
||||
|
||||
}
|
||||
|
||||
extras_dir[extras_dir_cnt++] = optarg;
|
||||
break;
|
||||
|
||||
case 't': { /* timeout */
|
||||
@ -828,10 +833,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
"Eißfeldt, Andrea Fioraldi and Dominik Maier");
|
||||
OKF("afl++ is open source, get it at "
|
||||
"https://github.com/AFLplusplus/AFLplusplus");
|
||||
OKF("Power schedules from github.com/mboehme/aflfast");
|
||||
OKF("Python Mutator and llvm_mode instrument file list from "
|
||||
"github.com/choller/afl");
|
||||
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
|
||||
|
||||
if (afl->sync_id && afl->is_main_node &&
|
||||
afl->afl_env.afl_custom_mutator_only) {
|
||||
@ -1132,14 +1133,23 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
setup_cmdline_file(afl, argv + optind);
|
||||
|
||||
read_testcases(afl);
|
||||
read_testcases(afl, NULL);
|
||||
// read_foreign_testcases(afl, 1); for the moment dont do this
|
||||
OKF("Loaded a total of %u seeds.", afl->queued_paths);
|
||||
|
||||
load_auto(afl);
|
||||
|
||||
pivot_inputs(afl);
|
||||
|
||||
if (extras_dir) { load_extras(afl, extras_dir); }
|
||||
if (extras_dir_cnt) {
|
||||
|
||||
for (i = 0; i < extras_dir_cnt; i++)
|
||||
load_extras(afl, extras_dir[i]);
|
||||
|
||||
dedup_extras(afl);
|
||||
OKF("Loaded a total of %u extras.", afl->extras_cnt);
|
||||
|
||||
}
|
||||
|
||||
if (!afl->timeout_given) { find_timeout(afl); }
|
||||
|
||||
|
488
src/afl-gcc.c
488
src/afl-gcc.c
@ -1,488 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - wrapper for GCC and clang
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This program is a drop-in replacement for GCC or clang. The most common way
|
||||
of using it is to pass the path to afl-gcc or afl-clang via CC when invoking
|
||||
./configure.
|
||||
|
||||
(Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.)
|
||||
|
||||
The wrapper needs to know the path to afl-as (renamed to 'as'). The default
|
||||
is /usr/local/lib/afl/. A convenient way to specify alternative directories
|
||||
would be to set AFL_PATH.
|
||||
|
||||
If AFL_HARDEN is set, the wrapper will compile the target app with various
|
||||
hardening options that may help detect memory management issues more
|
||||
reliably. You can also specify AFL_USE_ASAN to enable ASAN.
|
||||
|
||||
If you want to call a non-default compiler as a next step of the chain,
|
||||
specify its location via AFL_CC or AFL_CXX.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static u8 * as_path; /* Path to the AFL 'as' wrapper */
|
||||
static u8 **cc_params; /* Parameters passed to the real CC */
|
||||
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
|
||||
static u8 be_quiet, /* Quiet mode */
|
||||
clang_mode; /* Invoked as afl-clang*? */
|
||||
|
||||
/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived
|
||||
from argv[0]. If that fails, abort. */
|
||||
|
||||
static void find_as(u8 *argv0) {
|
||||
|
||||
u8 *afl_path = getenv("AFL_PATH");
|
||||
u8 *slash, *tmp;
|
||||
|
||||
if (afl_path) {
|
||||
|
||||
tmp = alloc_printf("%s/as", afl_path);
|
||||
|
||||
if (!access(tmp, X_OK)) {
|
||||
|
||||
as_path = afl_path;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
}
|
||||
|
||||
slash = strrchr(argv0, '/');
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8 *dir;
|
||||
|
||||
*slash = 0;
|
||||
dir = ck_strdup(argv0);
|
||||
*slash = '/';
|
||||
|
||||
tmp = alloc_printf("%s/afl-as", dir);
|
||||
|
||||
if (!access(tmp, X_OK)) {
|
||||
|
||||
as_path = dir;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
ck_free(dir);
|
||||
|
||||
}
|
||||
|
||||
if (!access(AFL_PATH "/as", X_OK)) {
|
||||
|
||||
as_path = AFL_PATH;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH");
|
||||
|
||||
}
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char **argv) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0;
|
||||
u8 *name;
|
||||
|
||||
#if defined(__FreeBSD__) && defined(WORD_SIZE_64)
|
||||
u8 m32_set = 0;
|
||||
#endif
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
|
||||
|
||||
name = strrchr(argv[0], '/');
|
||||
if (!name) {
|
||||
|
||||
name = argv[0];
|
||||
|
||||
/* This should never happen but fixes a scan-build warning */
|
||||
if (!name) { FATAL("Empty argv set"); }
|
||||
|
||||
} else {
|
||||
|
||||
++name;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(name, "afl-clang", 9)) {
|
||||
|
||||
clang_mode = 1;
|
||||
|
||||
setenv(CLANG_ENV_VAR, "1", 1);
|
||||
|
||||
if (!strcmp(name, "afl-clang++")) {
|
||||
|
||||
u8 *alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++";
|
||||
|
||||
} else if (!strcmp(name, "afl-clang")) {
|
||||
|
||||
u8 *alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang";
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
|
||||
FATAL("Name of the binary is not a known name, expected afl-clang(++)");
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* With GCJ and Eclipse installed, you can actually compile Java! The
|
||||
instrumentation will work (amazingly). Alas, unhandled exceptions do
|
||||
not call abort(), so afl-fuzz would need to be modified to equate
|
||||
non-zero exit codes with crash conditions when working with Java
|
||||
binaries. Meh. */
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
if (!strcmp(name, "afl-g++")) {
|
||||
|
||||
cc_params[0] = getenv("AFL_CXX");
|
||||
|
||||
} else if (!strcmp(name, "afl-gcj")) {
|
||||
|
||||
cc_params[0] = getenv("AFL_GCJ");
|
||||
|
||||
} else if (!strcmp(name, "afl-gcc")) {
|
||||
|
||||
cc_params[0] = getenv("AFL_CC");
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
|
||||
FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj");
|
||||
|
||||
}
|
||||
|
||||
if (!cc_params[0]) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"On Apple systems, 'gcc' is usually just a wrapper for clang. "
|
||||
"Please use the\n"
|
||||
" 'afl-clang' utility instead of 'afl-gcc'. If you really have "
|
||||
"GCC installed,\n"
|
||||
" set AFL_CC or AFL_CXX to specify the correct path to that "
|
||||
"compiler.\n");
|
||||
|
||||
FATAL("AFL_CC or AFL_CXX required on MacOS X");
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (!strcmp(name, "afl-g++")) {
|
||||
|
||||
u8 *alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++";
|
||||
|
||||
} else if (!strcmp(name, "afl-gcj")) {
|
||||
|
||||
u8 *alt_cc = getenv("AFL_GCJ");
|
||||
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj";
|
||||
|
||||
} else if (!strcmp(name, "afl-gcc")) {
|
||||
|
||||
u8 *alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc";
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
|
||||
FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj");
|
||||
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
}
|
||||
|
||||
while (--argc) {
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
if (!strncmp(cur, "-B", 2)) {
|
||||
|
||||
if (!be_quiet) { WARNF("-B is already set, overriding"); }
|
||||
|
||||
if (!cur[2] && argc > 1) {
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cur, "-integrated-as")) { continue; }
|
||||
|
||||
if (!strcmp(cur, "-pipe")) { continue; }
|
||||
|
||||
#if defined(__FreeBSD__) && defined(WORD_SIZE_64)
|
||||
if (!strcmp(cur, "-m32")) m32_set = 1;
|
||||
#endif
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") ||
|
||||
!strcmp(cur, "-fsanitize=memory")) {
|
||||
|
||||
asan_set = 1;
|
||||
|
||||
}
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) { fortify_set = 1; }
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-B";
|
||||
cc_params[cc_par_cnt++] = as_path;
|
||||
|
||||
if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; }
|
||||
|
||||
if (getenv("AFL_HARDEN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fstack-protector-all";
|
||||
|
||||
if (!fortify_set) { cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; }
|
||||
|
||||
}
|
||||
|
||||
if (asan_set) {
|
||||
|
||||
/* Pass this on to afl-as to adjust map density. */
|
||||
|
||||
setenv("AFL_USE_ASAN", "1", 1);
|
||||
|
||||
} else if (getenv("AFL_USE_ASAN")) {
|
||||
|
||||
if (getenv("AFL_USE_MSAN")) {
|
||||
|
||||
FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_HARDEN")) {
|
||||
|
||||
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=address";
|
||||
|
||||
} else if (getenv("AFL_USE_MSAN")) {
|
||||
|
||||
if (getenv("AFL_USE_ASAN")) {
|
||||
|
||||
FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_HARDEN")) {
|
||||
|
||||
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=memory";
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_USE_UBSAN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=undefined";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error";
|
||||
cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all";
|
||||
|
||||
}
|
||||
|
||||
#if defined(USEMMAP) && !defined(__HAIKU__)
|
||||
cc_params[cc_par_cnt++] = "-lrt";
|
||||
#endif
|
||||
|
||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
#if defined(__FreeBSD__) && defined(WORD_SIZE_64)
|
||||
|
||||
/* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself
|
||||
works OK. This has nothing to do with us, but let's avoid triggering
|
||||
that bug. */
|
||||
|
||||
if (!clang_mode || !m32_set) cc_params[cc_par_cnt++] = "-g";
|
||||
|
||||
#else
|
||||
|
||||
cc_params[cc_par_cnt++] = "-g";
|
||||
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt++] = "-O3";
|
||||
cc_params[cc_par_cnt++] = "-funroll-loops";
|
||||
|
||||
/* Two indicators that you're building for fuzzing; one of them is
|
||||
AFL-specific, the other is shared with libfuzzer. */
|
||||
|
||||
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
|
||||
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_NO_BUILTIN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-bcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
char *env_info =
|
||||
"Environment variables used by afl-gcc:\n"
|
||||
"AFL_CC: path to the C compiler to use\n"
|
||||
"AFL_CXX: path to the C++ compiler to use\n"
|
||||
"AFL_GCJ: path to the java compiler to use\n"
|
||||
"AFL_PATH: path to the instrumenting assembler\n"
|
||||
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_CAL_FAST: speed up the initial calibration\n"
|
||||
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_MSAN: activate memory sanitizer\n"
|
||||
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
|
||||
|
||||
"\nEnvironment variables used by afl-as (called by afl-gcc):\n"
|
||||
"AFL_AS: path to the assembler to use\n"
|
||||
"TMPDIR: set the directory for temporary files of afl-as\n"
|
||||
"TEMP: fall back path to directory for temporary files\n"
|
||||
"TMP: fall back path to directory for temporary files\n"
|
||||
"AFL_INST_RATIO: percentage of branches to instrument\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n"
|
||||
"AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n";
|
||||
|
||||
if (argc == 2 && strncmp(argv[1], "-h", 2) == 0) {
|
||||
|
||||
printf("afl-cc" VERSION " by Michal Zalewski\n\n");
|
||||
printf("%s \n\n", argv[0]);
|
||||
printf("afl-gcc has no command line options\n\n%s\n", env_info);
|
||||
printf(
|
||||
"NOTE: afl-gcc is deprecated, llvm_mode is much faster and has more "
|
||||
"options\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-cc" VERSION cRST " by Michal Zalewski\n");
|
||||
SAYF(cYEL "[!] " cBRI "NOTE: " cRST
|
||||
"afl-gcc is deprecated, llvm_mode is much faster and has more "
|
||||
"options\n");
|
||||
|
||||
} else {
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
|
||||
SAYF(
|
||||
"\n"
|
||||
"This is a helper application for afl-fuzz. It serves as a drop-in "
|
||||
"replacement\n"
|
||||
"for gcc or clang, letting you recompile third-party code with the "
|
||||
"required\n"
|
||||
"runtime instrumentation. A common use pattern would be one of the "
|
||||
"following:\n\n"
|
||||
|
||||
" CC=%s/afl-gcc ./configure\n"
|
||||
" CXX=%s/afl-g++ ./configure\n\n%s"
|
||||
|
||||
,
|
||||
BIN_PATH, BIN_PATH, env_info);
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
u8 *ptr;
|
||||
if (!be_quiet &&
|
||||
((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
|
||||
|
||||
u32 map_size = atoi(ptr);
|
||||
if (map_size != MAP_SIZE) {
|
||||
|
||||
WARNF("AFL_MAP_SIZE is not supported by afl-gcc");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
find_as(argv[0]);
|
||||
|
||||
edit_params(argc, argv);
|
||||
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
|
||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
. ./test-pre.sh
|
||||
|
||||
$ECHO "$BLUE[*] Testing: gcc_plugin"
|
||||
test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && {
|
||||
test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
|
||||
SAVE_AFL_CC=${AFL_CC}
|
||||
export AFL_CC=`command -v gcc`
|
||||
../afl-gcc-fast -o test-instr.plain.gccpi ../test-instr.c > /dev/null 2>&1
|
||||
|
@ -7,3 +7,5 @@ unset AFL_CC
|
||||
make -C .. unit || CODE=1 INCOMPLETE=1 :
|
||||
|
||||
. ./test-post.sh
|
||||
|
||||
rm -rf unittests/unit_hash unittests/unit_rand
|
||||
|
Reference in New Issue
Block a user