remove afl-gcc/afl-clang

This commit is contained in:
vanhauser-thc
2024-11-21 14:31:36 +01:00
parent 701e89bbcd
commit 7b24f4a329
22 changed files with 95 additions and 1789 deletions

View File

@ -30,12 +30,10 @@ INCLUDE_PATH = $(PREFIX)/include/afl
PROGNAME = afl PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
# PROGS intentionally omit afl-as, which gets installed elsewhere.
PROGS = 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-addseeds afl-system-config afl-persistent-config afl-cc SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
HEADERS = include/afl-as.h include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
ASAN_OPTIONS=detect_leaks=0 ASAN_OPTIONS=detect_leaks=0
SYS = $(shell uname -s) SYS = $(shell uname -s)
@ -327,10 +325,12 @@ ifdef TEST_MMAP
endif endif
.PHONY: all .PHONY: all
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done all: test_x86 test_shm test_python ready $(PROGS) llvm gcc_plugin test_build all_done
-$(MAKE) -C utils/aflpp_driver -$(MAKE) -C utils/aflpp_driver
@echo @echo
@echo @echo
@echo
@echo
@echo Build Summary: @echo Build Summary:
@test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler" @test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md" @test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@ -339,6 +339,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
ifneq "$(SYS)" "Darwin" ifneq "$(SYS)" "Darwin"
@test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this" @test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
endif endif
@test -e afl-cc || echo "[-] AFL++ instrumentation compilers could not be built! Install llvm-VERSION-dev or gcc-VERSION-plugin-dev, see docs/INSTALL.md!"
@echo @echo
.PHONY: llvm .PHONY: llvm
@ -465,10 +466,6 @@ endif
ready: ready:
@echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))" @echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))"
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
$(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o $(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
@ -576,7 +573,7 @@ code-format:
.PHONY: test_build .PHONY: test_build
ifndef AFL_NO_X86 ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap test_build: afl-cc afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
-ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null -ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null
@ -585,18 +582,18 @@ test_build: afl-cc afl-gcc afl-as afl-showmap
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc 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 @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc 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
@echo "[+] All right, the instrumentation of afl-cc seems to be working!" @echo "[+] All right, the instrumentation of afl-cc seems to be working!"
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." # @echo "[*] Testing the CC wrapper and its instrumentation output..."
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-clang-fast test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-clang-fast failed"; exit 1 )
# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # 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 # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
# @rm -f 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 of afl-gcc does not seem to be behaving correctly!"; \ # @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-clang-fast does not seem to be behaving correctly!"; \
# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \ # gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi # ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
# @echo # @echo
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!" # @echo "[+] All right, the instrumentation of afl-clang-fast seems to be working!"
else else
test_build: afl-cc afl-as afl-showmap test_build: afl-cc afl-showmap
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)." @echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
endif endif
@ -606,7 +603,8 @@ all_done: test_build
@test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!" @test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/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 build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, 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 build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.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 build, 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." @test -e afl-cc && echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
@test -e afl-cc || echo "[-] ERROR - neither afl-clang-fast or afl-gcc-fast could be compiled - YOU ARE MISSING PACKAGES! Read docs/INSTALL.md!"
@if [ "$(SYS)" = "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 for fuzzing software not\nspecifically for MacOS.\n\n"; fi @if [ "$(SYS)" = "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 for fuzzing software not\nspecifically for MacOS.\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 @! 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
@ -614,7 +612,7 @@ all_done: test_build
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf $(PROGS) 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-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a rm -rf $(PROGS) afl-fuzz-document 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-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
-$(MAKE) -f GNUmakefile.llvm clean -$(MAKE) -f GNUmakefile.llvm clean
-$(MAKE) -f GNUmakefile.gcc_plugin clean -$(MAKE) -f GNUmakefile.gcc_plugin clean
-$(MAKE) -C utils/libdislocator clean -$(MAKE) -C utils/libdislocator clean
@ -831,8 +829,6 @@ endif
install -m 644 $(HEADERS) $${DESTDIR}$(INCLUDE_PATH) install -m 644 $(HEADERS) $${DESTDIR}$(INCLUDE_PATH)
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH) @mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
install -m0644 *.8 ${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) install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
cp -r testcases/ $${DESTDIR}$(MISC_PATH) cp -r testcases/ $${DESTDIR}$(MISC_PATH)
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH) cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
@ -840,9 +836,9 @@ endif
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall:
-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-client afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto* -cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-client afl-network-server afl-g* afl-plot.sh afl-ld-lto afl-c* afl-lto*
-cd $${DESTDIR}$(INCLUDE_PATH) && rm -f $(HEADERS:include/%=%) -cd $${DESTDIR}$(INCLUDE_PATH) && rm -f $(HEADERS:include/%=%)
-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt injections.dic -cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt injections.dic
-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries -rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f" -sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
-cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES) -cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)

View File

@ -45,14 +45,10 @@ fairly broad use of environment variables instead:
make make
``` ```
- Setting `AFL_AS`, `AFL_CC`, and `AFL_CXX` lets you use alternate downstream - Setting `AFL_CC`, and `AFL_CXX` lets you use alternate downstream
compilation tools, rather than the default 'as', 'clang', or 'gcc' binaries compilation tools, rather than the default 'clang', or 'gcc' binaries
in your `$PATH`. in your `$PATH`.
- 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`
- Most AFL tools do not print any output if stdout/stderr are redirected. If - Most AFL tools do not print any output if stdout/stderr are redirected. If
you want to get the output into a file, then set the `AFL_DEBUG` environment you want to get the output into a file, then set the `AFL_DEBUG` environment
variable. This is sadly necessary for various build processes which fail variable. This is sadly necessary for various build processes which fail
@ -83,17 +79,13 @@ fairly broad use of environment variables instead:
Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only
the transitions between function entry points, but not individual branches. the transitions between function entry points, but not individual branches.
Note that this is an outdated variable. A few instances (e.g., afl-gcc) Note that this is an outdated variable. Only LLVM CLASSIC pass can use this.
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 - `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). libtokencap.so (but perhaps running a bit slower than without the flag).
- `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as. - `AFL_PATH` can be used to point a directory that contains LLVM/GCC plugins
One possible use of this is utils/clang_asm_normalize/, which lets you for AFL++, AFL++'s runtime objects and QEMU/Frida support files.
instrument hand-written assembly when compiling clang code by plugging a
normalizer into the chain. (There is no equivalent feature for GCC.)
- Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being - Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being
displayed during compilation, in case you find them distracting. displayed during compilation, in case you find them distracting.

View File

@ -6,20 +6,22 @@ QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
## Features and instrumentation ## Features and instrumentation
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) | Note that afl-gcc and afl-clang have been removed because their instrumentation is absolutely outdated.
| ------------------------------|:--------:|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
| Threadsafe counters [A] | | x(3) | | | | | x | | | Feature/Instrumentation | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) |
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | | | ------------------------------|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | | | Threadsafe counters [A] | x(3) | | | | | x | |
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | | | NeverZero [B] | x(1) | x | x | x | x | | |
| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | | | Persistent Mode [C] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
| Selective Instrumentation [F] | | x | x | x | x | | | | | LAF-Intel / CompCov [D] | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | | | CmpLog [E] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | | | Selective Instrumentation [F] | x | x | x | x | | | |
| Context Coverage [I] | | x(6) | | | | | | | | Non-Colliding Coverage [G] | x(4) | | | (x)(5) | | | |
| Auto Dictionary [J] | | x(7) | | | | | | | | Ngram prev_loc Coverage [H] | x(6) | | | | | | |
| Snapshot Support [K] | | (x)(8) | (x)(8) | | (x)(5) | | x | | | Context Coverage [I] | x(6) | | | | | | |
| Shared Memory Test cases [L] | | x | x | x86[_64]/arm64 | x | x | x | | | Auto Dictionary [J] | x(7) | | | | | | |
| Snapshot Support [K] | (x)(8) | (x)(8) | | (x)(5) | | x | |
| Shared Memory Test cases [L] | x | x | x86[_64]/arm64 | x | x | x | |
## More information about features ## More information about features
@ -94,7 +96,7 @@ L. Faster fuzzing and less kernel syscall overhead by in-memory fuzz testcase
Among others, the following features and patches have been integrated: Among others, the following features and patches have been integrated:
* NeverZero patch for afl-gcc, instrumentation, QEMU mode and unicorn_mode which * NeverZero for llvm/gcc instrumentation, QEMU mode and unicorn_mode which
prevents a wrapping map value to zero, increases coverage prevents a wrapping map value to zero, increases coverage
* Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode * Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode
* Unicorn mode which allows fuzzing of binaries from completely different * Unicorn mode which allows fuzzing of binaries from completely different

View File

@ -200,6 +200,7 @@ have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
x86_64 - still has it's symbols and compiled with position independent code x86_64 - still has it's symbols and compiled with position independent code
(PIC/PIE), then the RetroWrite solution might be for you. (PIC/PIE), then the RetroWrite solution might be for you.
It decompiles to ASM files which can then be instrumented with afl-gcc. It decompiles to ASM files which can then be instrumented with afl-gcc.
Note that afl-gcc is only present until AFL++ v4.21c and was subsequently removed as it is obsolete.
Binaries that are statically instrumented for fuzzing using RetroWrite are close Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based in performance to compiler-instrumented binaries and outperform the QEMU-based

View File

@ -61,6 +61,8 @@ evaluation flow will help you to select the best possible.
It is highly recommended to have the newest llvm version possible installed, It is highly recommended to have the newest llvm version possible installed,
anything below 9 is not recommended. anything below 9 is not recommended.
IMPORTANT NOTICE: afl-gcc/afl-clang have been removed from AFL++ as they are obsolete.
``` ```
+--------------------------------+ +--------------------------------+
| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++) | clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++)
@ -84,7 +86,7 @@ anything below 9 is not recommended.
| if not, or if you do not have a gcc with plugin support | if not, or if you do not have a gcc with plugin support
| |
v v
use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang) GAME OVER! Install gcc-VERSION-plugin-dev or llvm-VERSION-dev
``` ```
Clickable README links for the chosen compiler: Clickable README links for the chosen compiler:
@ -92,14 +94,12 @@ Clickable README links for the chosen compiler:
* [LTO mode - afl-clang-lto](../instrumentation/README.lto.md) * [LTO mode - afl-clang-lto](../instrumentation/README.lto.md)
* [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.md) * [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.md)
* [GCC_PLUGIN mode - afl-gcc-fast](../instrumentation/README.gcc_plugin.md) * [GCC_PLUGIN mode - afl-gcc-fast](../instrumentation/README.gcc_plugin.md)
* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own
features
You can select the mode for the afl-cc compiler by one of the following methods: You can select the mode for the afl-cc compiler by one of the following methods:
* Using a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, * Using a symlink to afl-cc:
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
afl-gcc-fast, afl-g++-fast (recommended!). afl-gcc-fast, afl-g++-fast.
* Using the environment variable `AFL_CC_COMPILER` with `MODE`. * Using the environment variable `AFL_CC_COMPILER` with `MODE`.
* Passing --afl-`MODE` command line options to the compiler via * Passing --afl-`MODE` command line options to the compiler via
`CFLAGS`/`CXXFLAGS`/`CPPFLAGS`. `CFLAGS`/`CXXFLAGS`/`CPPFLAGS`.
@ -108,8 +108,7 @@ You can select the mode for the afl-cc compiler by one of the following methods:
* LTO (afl-clang-lto*) * LTO (afl-clang-lto*)
* LLVM (afl-clang-fast*) * LLVM (afl-clang-fast*)
* GCC_PLUGIN (afl-g*-fast) or GCC (afl-gcc/afl-g++) * GCC_PLUGIN (afl-g*-fast)
* CLANG(afl-clang/afl-clang++)
Because no AFL++ specific command-line options are accepted (beside the Because no AFL++ specific command-line options are accepted (beside the
--afl-MODE command), the compile-time tools make fairly broad use of environment --afl-MODE command), the compile-time tools make fairly broad use of environment

View File

@ -1,775 +0,0 @@
/*
american fuzzy lop++ - injectable parts
---------------------------------------
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eissfeldt <heiko.eissfeldt@hexco.de>,
Andrea Fioraldi <andreafioraldi@gmail.com>,
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2024 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:
https://www.apache.org/licenses/LICENSE-2.0
This file houses the assembly-level instrumentation injected into fuzzed
programs. The instrumentation stores XORed pairs of data: identifiers of the
currently executing branch and the one that executed immediately before.
TL;DR: the instrumentation does shm_trace_map[cur_loc ^ prev_loc]++
The code is designed for 32-bit and 64-bit x86 systems. Both modes should
work everywhere except for Apple systems. Apple does relocations differently
from everybody else, so since their OSes have been 64-bit for a longer while,
I didn't go through the mental effort of porting the 32-bit code.
In principle, similar code should be easy to inject into any well-behaved
binary-only code (e.g., using DynamoRIO). Conditional jumps offer natural
targets for instrumentation, and should offer comparable probe density.
*/
#ifndef _HAVE_AFL_AS_H
#define _HAVE_AFL_AS_H
#include "config.h"
#include "types.h"
/*
------------------
Performances notes
------------------
Contributions to make this code faster are appreciated! Here are some
rough notes that may help with the task:
- Only the trampoline_fmt and the non-setup __afl_maybe_log code paths are
really worth optimizing; the setup / fork server stuff matters a lot less
and should be mostly just kept readable.
- We're aiming for modern CPUs with out-of-order execution and large
pipelines; the code is mostly follows intuitive, human-readable
instruction ordering, because "textbook" manual reorderings make no
substantial difference.
- Interestingly, instrumented execution isn't a lot faster if we store a
variable pointer to the setup, log, or return routine and then do a reg
call from within trampoline_fmt. It does speed up non-instrumented
execution quite a bit, though, since that path just becomes
push-call-ret-pop.
- There is also not a whole lot to be gained by doing SHM attach at a
fixed address instead of retrieving __afl_area_ptr. Although it allows us
to have a shorter log routine inserted for conditional jumps and jump
labels (for a ~10% perf gain), there is a risk of bumping into other
allocations created by the program or by tools such as ASAN.
- popf is *awfully* slow, which is why we're doing the lahf / sahf +
overflow test trick. Unfortunately, this forces us to taint eax / rax, but
this dependency on a commonly-used register still beats the alternative of
using pushf / popf.
One possible optimization is to avoid touching flags by using a circular
buffer that stores just a sequence of current locations, with the XOR stuff
happening offline. Alas, this doesn't seem to have a huge impact:
https://groups.google.com/d/msg/afl-users/MsajVf4fRLo/2u6t88ntUBIJ
- Preforking one child a bit sooner, and then waiting for the "go" command
from within the child, doesn't offer major performance gains; fork() seems
to be relatively inexpensive these days. Preforking multiple children does
help, but badly breaks the "~1 core per fuzzer" design, making it harder to
scale up. Maybe there is some middle ground.
Perhaps of note: in the 64-bit version for all platforms except for Apple,
the instrumentation is done slightly differently than on 32-bit, with
__afl_prev_loc and __afl_area_ptr being local to the object file (.lcomm),
rather than global (.comm). This is to avoid GOTRELPC lookups in the critical
code path, which AFAICT, are otherwise unavoidable if we want gcc -shared to
work; simple relocations between .bss and .text won't work on most 64-bit
platforms in such a case.
(Fun fact: on Apple systems, .lcomm can segfault the linker.)
The side effect is that state transitions are measured in a somewhat
different way, with previous tuple being recorded separately within the scope
of every .c file. This should have no impact in any practical sense.
Another side effect of this design is that getenv() will be called once per
every .o file when running in non-instrumented mode; and since getenv() tends
to be optimized in funny ways, we need to be very careful to save every
oddball register it may touch.
*/
static const u8 *trampoline_fmt_32 =
"\n"
"/* --- AFL TRAMPOLINE (32-BIT) --- */\n"
"\n"
".align 4\n"
"\n"
"leal -16(%%esp), %%esp\n"
"movl %%edi, 0(%%esp)\n"
"movl %%edx, 4(%%esp)\n"
"movl %%ecx, 8(%%esp)\n"
"movl %%eax, 12(%%esp)\n"
"movl $0x%08x, %%ecx\n"
"call __afl_maybe_log\n"
"movl 12(%%esp), %%eax\n"
"movl 8(%%esp), %%ecx\n"
"movl 4(%%esp), %%edx\n"
"movl 0(%%esp), %%edi\n"
"leal 16(%%esp), %%esp\n"
"\n"
"/* --- END --- */\n"
"\n";
static const u8 *trampoline_fmt_64 =
"\n"
"/* --- AFL TRAMPOLINE (64-BIT) --- */\n"
"\n"
".align 4\n"
"\n"
"leaq -(128+24)(%%rsp), %%rsp\n"
"movq %%rdx, 0(%%rsp)\n"
"movq %%rcx, 8(%%rsp)\n"
"movq %%rax, 16(%%rsp)\n"
"movq $0x%08x, %%rcx\n"
"call __afl_maybe_log\n"
"movq 16(%%rsp), %%rax\n"
"movq 8(%%rsp), %%rcx\n"
"movq 0(%%rsp), %%rdx\n"
"leaq (128+24)(%%rsp), %%rsp\n"
"\n"
"/* --- END --- */\n"
"\n";
static const u8 *main_payload_32 =
"\n"
"/* --- AFL MAIN PAYLOAD (32-BIT) --- */\n"
"\n"
".text\n"
".att_syntax\n"
".code32\n"
".align 8\n"
"\n"
"__afl_maybe_log:\n"
"\n"
" lahf\n"
" seto %al\n"
"\n"
" /* Check if SHM region is already mapped. */\n"
"\n"
" movl __afl_area_ptr, %edx\n"
" testl %edx, %edx\n"
" je __afl_setup\n"
"\n"
"__afl_store:\n"
"\n"
" /* Calculate and store hit for the code location specified in ecx. There\n"
" is a double-XOR way of doing this without tainting another register,\n"
" and we use it on 64-bit systems; but it's slower for 32-bit ones. */\n"
"\n"
#ifndef COVERAGE_ONLY
" movl __afl_prev_loc, %edi\n"
" xorl %ecx, %edi\n"
" shrl $1, %ecx\n"
" movl %ecx, __afl_prev_loc\n"
#else
" movl %ecx, %edi\n"
#endif /* ^!COVERAGE_ONLY */
"\n"
#ifdef SKIP_COUNTS
" orb $1, (%edx, %edi, 1)\n"
#else
" addb $1, (%edx, %edi, 1)\n"
" adcb $0, (%edx, %edi, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
#endif /* ^SKIP_COUNTS */
"\n"
"__afl_return:\n"
"\n"
" addb $127, %al\n"
" sahf\n"
" ret\n"
"\n"
".align 8\n"
"\n"
"__afl_setup:\n"
"\n"
" /* Do not retry setup if we had previous failures. */\n"
"\n"
" cmpb $0, __afl_setup_failure\n"
" jne __afl_return\n"
"\n"
" /* Map SHM, jumping to __afl_setup_abort if something goes wrong.\n"
" We do not save FPU/MMX/SSE registers here, but hopefully, nobody\n"
" will notice this early in the game. */\n"
"\n"
" pushl %eax\n"
" pushl %ecx\n"
"\n"
" pushl $.AFL_SHM_ENV\n"
" call getenv\n"
" addl $4, %esp\n"
"\n"
" testl %eax, %eax\n"
" je __afl_setup_abort\n"
"\n"
#ifdef USEMMAP
" pushl $384 /* shm_open mode 0600 */\n"
" pushl $2 /* flags O_RDWR */\n"
" pushl %eax /* SHM file path */\n"
" call shm_open\n"
" addl $12, %esp\n"
"\n"
" cmpl $-1, %eax\n"
" je __afl_setup_abort\n"
"\n"
" pushl $0 /* mmap off */\n"
" pushl %eax /* shm fd */\n"
" pushl $1 /* mmap flags */\n"
" pushl $3 /* mmap prot */\n"
" pushl $"STRINGIFY(MAP_SIZE)" /* mmap len */\n"
" pushl $0 /* mmap addr */\n"
" call mmap\n"
" addl $12, %esp\n"
"\n"
" cmpl $-1, %eax\n"
" je __afl_setup_abort\n"
"\n"
#else
" pushl %eax\n"
" call atoi\n"
" addl $4, %esp\n"
"\n"
" pushl $0 /* shmat flags */\n"
" pushl $0 /* requested addr */\n"
" pushl %eax /* SHM ID */\n"
" call shmat\n"
" addl $12, %esp\n"
"\n"
" cmpl $-1, %eax\n"
" je __afl_setup_abort\n"
"\n"
#endif
" movb $1, (%eax)\n"
" /* Store the address of the SHM region. */\n"
"\n"
" movl %eax, __afl_area_ptr\n"
" movl %eax, %edx\n"
"\n"
" popl %ecx\n"
" popl %eax\n"
"\n"
"__afl_forkserver:\n"
"\n"
" /* Enter the fork server mode to avoid the overhead of execve() calls. */\n"
"\n"
" pushl %eax\n"
" pushl %ecx\n"
" pushl %edx\n"
"\n"
" /* Phone home and tell the parent that we're OK. (Note that signals with\n"
" no SA_RESTART will mess it up). If this fails, assume that the fd is\n"
" closed because we were execve()d from an instrumented binary, or because\n"
" the parent doesn't want to use the fork server. */\n"
"\n"
" pushl $4 /* length */\n"
" pushl $__afl_temp /* data */\n"
" pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
" call write\n"
" addl $12, %esp\n"
"\n"
" cmpl $4, %eax\n"
" jne __afl_fork_resume\n"
"\n"
"__afl_fork_wait_loop:\n"
"\n"
" /* Wait for parent by reading from the pipe. Abort if read fails. */\n"
"\n"
" pushl $4 /* length */\n"
" pushl $__afl_temp /* data */\n"
" pushl $" STRINGIFY(FORKSRV_FD) " /* file desc */\n"
" call read\n"
" addl $12, %esp\n"
"\n"
" cmpl $4, %eax\n"
" jne __afl_die\n"
"\n"
" /* Once woken up, create a clone of our process. This is an excellent use\n"
" case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"
" caches getpid() results and offers no way to update the value, breaking\n"
" abort(), raise(), and a bunch of other things :-( */\n"
"\n"
" call fork\n"
"\n"
" cmpl $0, %eax\n"
" jl __afl_die\n"
" je __afl_fork_resume\n"
"\n"
" /* In parent process: write PID to pipe, then wait for child. */\n"
"\n"
" movl %eax, __afl_fork_pid\n"
"\n"
" pushl $4 /* length */\n"
" pushl $__afl_fork_pid /* data */\n"
" pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
" call write\n"
" addl $12, %esp\n"
"\n"
" pushl $0 /* no flags */\n"
" pushl $__afl_temp /* status */\n"
" pushl __afl_fork_pid /* PID */\n"
" call waitpid\n"
" addl $12, %esp\n"
"\n"
" cmpl $0, %eax\n"
" jle __afl_die\n"
"\n"
" /* Relay wait status to pipe, then loop back. */\n"
"\n"
" pushl $4 /* length */\n"
" pushl $__afl_temp /* data */\n"
" pushl $" STRINGIFY((FORKSRV_FD + 1)) " /* file desc */\n"
" call write\n"
" addl $12, %esp\n"
"\n"
" jmp __afl_fork_wait_loop\n"
"\n"
"__afl_fork_resume:\n"
"\n"
" /* In child process: close fds, resume execution. */\n"
"\n"
" pushl $" STRINGIFY(FORKSRV_FD) "\n"
" call close\n"
"\n"
" pushl $" STRINGIFY((FORKSRV_FD + 1)) "\n"
" call close\n"
"\n"
" addl $8, %esp\n"
"\n"
" popl %edx\n"
" popl %ecx\n"
" popl %eax\n"
" jmp __afl_store\n"
"\n"
"__afl_die:\n"
"\n"
" xorl %eax, %eax\n"
" call _exit\n"
"\n"
"__afl_setup_abort:\n"
"\n"
" /* Record setup failure so that we don't keep calling\n"
" shmget() / shmat() over and over again. */\n"
"\n"
" incb __afl_setup_failure\n"
" popl %ecx\n"
" popl %eax\n"
" jmp __afl_return\n"
"\n"
".AFL_VARS:\n"
"\n"
" .comm __afl_area_ptr, 4, 32\n"
" .comm __afl_setup_failure, 1, 32\n"
#ifndef COVERAGE_ONLY
" .comm __afl_prev_loc, 4, 32\n"
#endif /* !COVERAGE_ONLY */
" .comm __afl_final_loc, 4, 32\n"
" .comm __afl_fork_pid, 4, 32\n"
" .comm __afl_temp, 4, 32\n"
"\n"
".AFL_SHM_ENV:\n"
" .asciz \"" SHM_ENV_VAR "\"\n"
"\n"
"/* --- END --- */\n"
"\n";
/* The OpenBSD hack is due to lahf and sahf not being recognized by some
versions of binutils: https://marc.info/?l=openbsd-cvs&m=141636589924400
The Apple code is a bit different when calling libc functions because
they are doing relocations differently from everybody else. We also need
to work around the crash issue with .lcomm and the fact that they don't
recognize .string. */
#ifdef __APPLE__
#define CALL_L64(str) "call _" str "\n"
#else
#define CALL_L64(str) "call " str "@PLT\n"
#endif /* ^__APPLE__ */
static const u8 *main_payload_64 =
"\n"
"/* --- AFL MAIN PAYLOAD (64-BIT) --- */\n"
"\n"
".text\n"
".att_syntax\n"
".code64\n"
".align 8\n"
"\n"
"__afl_maybe_log:\n"
"\n"
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
" .byte 0x9f /* lahf */\n"
#else
" lahf\n"
#endif /* ^__OpenBSD__, etc */
" seto %al\n"
"\n"
" /* Check if SHM region is already mapped. */\n"
"\n"
" movq __afl_area_ptr(%rip), %rdx\n"
" testq %rdx, %rdx\n"
" je __afl_setup\n"
"\n"
"__afl_store:\n"
"\n"
" /* Calculate and store hit for the code location specified in rcx. */\n"
"\n"
#ifndef COVERAGE_ONLY
" xorq __afl_prev_loc(%rip), %rcx\n"
" xorq %rcx, __afl_prev_loc(%rip)\n"
" shrq $1, __afl_prev_loc(%rip)\n"
#endif /* ^!COVERAGE_ONLY */
"\n"
#ifdef SKIP_COUNTS
" orb $1, (%rdx, %rcx, 1)\n"
#else
" addb $1, (%rdx, %rcx, 1)\n"
" adcb $0, (%rdx, %rcx, 1)\n" // never zero counter implementation. slightly better path discovery and little performance impact
#endif /* ^SKIP_COUNTS */
"\n"
"__afl_return:\n"
"\n"
" addb $127, %al\n"
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
" .byte 0x9e /* sahf */\n"
#else
" sahf\n"
#endif /* ^__OpenBSD__, etc */
" ret\n"
"\n"
".align 8\n"
"\n"
"__afl_setup:\n"
"\n"
" /* Do not retry setup if we had previous failures. */\n"
"\n"
" cmpb $0, __afl_setup_failure(%rip)\n"
" jne __afl_return\n"
"\n"
" /* Check out if we have a global pointer on file. */\n"
"\n"
#ifndef __APPLE__
" movq __afl_global_area_ptr@GOTPCREL(%rip), %rdx\n"
" movq (%rdx), %rdx\n"
#else
" movq __afl_global_area_ptr(%rip), %rdx\n"
#endif /* !^__APPLE__ */
" testq %rdx, %rdx\n"
" je __afl_setup_first\n"
"\n"
" movq %rdx, __afl_area_ptr(%rip)\n"
" jmp __afl_store\n"
"\n"
"__afl_setup_first:\n"
"\n"
" /* Save everything that is not yet saved and that may be touched by\n"
" getenv() and several other libcalls we'll be relying on. */\n"
"\n"
" leaq -352(%rsp), %rsp\n"
"\n"
" movq %rax, 0(%rsp)\n"
" movq %rcx, 8(%rsp)\n"
" movq %rdi, 16(%rsp)\n"
" movq %rsi, 32(%rsp)\n"
" movq %r8, 40(%rsp)\n"
" movq %r9, 48(%rsp)\n"
" movq %r10, 56(%rsp)\n"
" movq %r11, 64(%rsp)\n"
"\n"
" movq %xmm0, 96(%rsp)\n"
" movq %xmm1, 112(%rsp)\n"
" movq %xmm2, 128(%rsp)\n"
" movq %xmm3, 144(%rsp)\n"
" movq %xmm4, 160(%rsp)\n"
" movq %xmm5, 176(%rsp)\n"
" movq %xmm6, 192(%rsp)\n"
" movq %xmm7, 208(%rsp)\n"
" movq %xmm8, 224(%rsp)\n"
" movq %xmm9, 240(%rsp)\n"
" movq %xmm10, 256(%rsp)\n"
" movq %xmm11, 272(%rsp)\n"
" movq %xmm12, 288(%rsp)\n"
" movq %xmm13, 304(%rsp)\n"
" movq %xmm14, 320(%rsp)\n"
" movq %xmm15, 336(%rsp)\n"
"\n"
" /* Map SHM, jumping to __afl_setup_abort if something goes wrong. */\n"
"\n"
" /* The 64-bit ABI requires 16-byte stack alignment. We'll keep the\n"
" original stack ptr in the callee-saved r12. */\n"
"\n"
" pushq %r12\n"
" movq %rsp, %r12\n"
" subq $16, %rsp\n"
" andq $0xfffffffffffffff0, %rsp\n"
"\n"
" leaq .AFL_SHM_ENV(%rip), %rdi\n"
CALL_L64("getenv")
"\n"
" testq %rax, %rax\n"
" je __afl_setup_abort\n"
"\n"
#ifdef USEMMAP
" movl $384, %edx /* shm_open mode 0600 */\n"
" movl $2, %esi /* flags O_RDWR */\n"
" movq %rax, %rdi /* SHM file path */\n"
CALL_L64("shm_open")
"\n"
" cmpq $-1, %rax\n"
" je __afl_setup_abort\n"
"\n"
" movl $0, %r9d\n"
" movl %eax, %r8d\n"
" movl $1, %ecx\n"
" movl $3, %edx\n"
" movl $"STRINGIFY(MAP_SIZE)", %esi\n"
" movl $0, %edi\n"
CALL_L64("mmap")
"\n"
" cmpq $-1, %rax\n"
" je __afl_setup_abort\n"
"\n"
#else
" movq %rax, %rdi\n"
CALL_L64("atoi")
"\n"
" xorq %rdx, %rdx /* shmat flags */\n"
" xorq %rsi, %rsi /* requested addr */\n"
" movq %rax, %rdi /* SHM ID */\n"
CALL_L64("shmat")
"\n"
" cmpq $-1, %rax\n"
" je __afl_setup_abort\n"
"\n"
#endif
" movb $1, (%rax)\n"
" /* Store the address of the SHM region. */\n"
"\n"
" movq %rax, %rdx\n"
" movq %rax, __afl_area_ptr(%rip)\n"
"\n"
#ifdef __APPLE__
" movq %rax, __afl_global_area_ptr(%rip)\n"
#else
" movq __afl_global_area_ptr@GOTPCREL(%rip), %rdx\n"
" movq %rax, (%rdx)\n"
#endif /* ^__APPLE__ */
" movq %rax, %rdx\n"
"\n"
"__afl_forkserver:\n"
"\n"
" /* Enter the fork server mode to avoid the overhead of execve() calls. We\n"
" push rdx (area ptr) twice to keep stack alignment neat. */\n"
"\n"
" pushq %rdx\n"
" pushq %rdx\n"
"\n"
" /* Phone home and tell the parent that we're OK. (Note that signals with\n"
" no SA_RESTART will mess it up). If this fails, assume that the fd is\n"
" closed because we were execve()d from an instrumented binary, or because\n"
" the parent doesn't want to use the fork server. */\n"
"\n"
" movq $4, %rdx /* length */\n"
" leaq __afl_temp(%rip), %rsi /* data */\n"
" movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
CALL_L64("write")
"\n"
" cmpq $4, %rax\n"
" jne __afl_fork_resume\n"
"\n"
"__afl_fork_wait_loop:\n"
"\n"
" /* Wait for parent by reading from the pipe. Abort if read fails. */\n"
"\n"
" movq $4, %rdx /* length */\n"
" leaq __afl_temp(%rip), %rsi /* data */\n"
" movq $" STRINGIFY(FORKSRV_FD) ", %rdi /* file desc */\n"
CALL_L64("read")
" cmpq $4, %rax\n"
" jne __afl_die\n"
"\n"
" /* Once woken up, create a clone of our process. This is an excellent use\n"
" case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"
" caches getpid() results and offers no way to update the value, breaking\n"
" abort(), raise(), and a bunch of other things :-( */\n"
"\n"
CALL_L64("fork")
" cmpq $0, %rax\n"
" jl __afl_die\n"
" je __afl_fork_resume\n"
"\n"
" /* In parent process: write PID to pipe, then wait for child. */\n"
"\n"
" movl %eax, __afl_fork_pid(%rip)\n"
"\n"
" movq $4, %rdx /* length */\n"
" leaq __afl_fork_pid(%rip), %rsi /* data */\n"
" movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
CALL_L64("write")
"\n"
" movq $0, %rdx /* no flags */\n"
" leaq __afl_temp(%rip), %rsi /* status */\n"
" movq __afl_fork_pid(%rip), %rdi /* PID */\n"
CALL_L64("waitpid")
" cmpq $0, %rax\n"
" jle __afl_die\n"
"\n"
" /* Relay wait status to pipe, then loop back. */\n"
"\n"
" movq $4, %rdx /* length */\n"
" leaq __afl_temp(%rip), %rsi /* data */\n"
" movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi /* file desc */\n"
CALL_L64("write")
"\n"
" jmp __afl_fork_wait_loop\n"
"\n"
"__afl_fork_resume:\n"
"\n"
" /* In child process: close fds, resume execution. */\n"
"\n"
" movq $" STRINGIFY(FORKSRV_FD) ", %rdi\n"
CALL_L64("close")
"\n"
" movq $" STRINGIFY((FORKSRV_FD + 1)) ", %rdi\n"
CALL_L64("close")
"\n"
" popq %rdx\n"
" popq %rdx\n"
"\n"
" movq %r12, %rsp\n"
" popq %r12\n"
"\n"
" movq 0(%rsp), %rax\n"
" movq 8(%rsp), %rcx\n"
" movq 16(%rsp), %rdi\n"
" movq 32(%rsp), %rsi\n"
" movq 40(%rsp), %r8\n"
" movq 48(%rsp), %r9\n"
" movq 56(%rsp), %r10\n"
" movq 64(%rsp), %r11\n"
"\n"
" movq 96(%rsp), %xmm0\n"
" movq 112(%rsp), %xmm1\n"
" movq 128(%rsp), %xmm2\n"
" movq 144(%rsp), %xmm3\n"
" movq 160(%rsp), %xmm4\n"
" movq 176(%rsp), %xmm5\n"
" movq 192(%rsp), %xmm6\n"
" movq 208(%rsp), %xmm7\n"
" movq 224(%rsp), %xmm8\n"
" movq 240(%rsp), %xmm9\n"
" movq 256(%rsp), %xmm10\n"
" movq 272(%rsp), %xmm11\n"
" movq 288(%rsp), %xmm12\n"
" movq 304(%rsp), %xmm13\n"
" movq 320(%rsp), %xmm14\n"
" movq 336(%rsp), %xmm15\n"
"\n"
" leaq 352(%rsp), %rsp\n"
"\n"
" jmp __afl_store\n"
"\n"
"__afl_die:\n"
"\n"
" xorq %rax, %rax\n"
CALL_L64("_exit")
"\n"
"__afl_setup_abort:\n"
"\n"
" /* Record setup failure so that we don't keep calling\n"
" shmget() / shmat() over and over again. */\n"
"\n"
" incb __afl_setup_failure(%rip)\n"
"\n"
" movq %r12, %rsp\n"
" popq %r12\n"
"\n"
" movq 0(%rsp), %rax\n"
" movq 8(%rsp), %rcx\n"
" movq 16(%rsp), %rdi\n"
" movq 32(%rsp), %rsi\n"
" movq 40(%rsp), %r8\n"
" movq 48(%rsp), %r9\n"
" movq 56(%rsp), %r10\n"
" movq 64(%rsp), %r11\n"
"\n"
" movq 96(%rsp), %xmm0\n"
" movq 112(%rsp), %xmm1\n"
" movq 128(%rsp), %xmm2\n"
" movq 144(%rsp), %xmm3\n"
" movq 160(%rsp), %xmm4\n"
" movq 176(%rsp), %xmm5\n"
" movq 192(%rsp), %xmm6\n"
" movq 208(%rsp), %xmm7\n"
" movq 224(%rsp), %xmm8\n"
" movq 240(%rsp), %xmm9\n"
" movq 256(%rsp), %xmm10\n"
" movq 272(%rsp), %xmm11\n"
" movq 288(%rsp), %xmm12\n"
" movq 304(%rsp), %xmm13\n"
" movq 320(%rsp), %xmm14\n"
" movq 336(%rsp), %xmm15\n"
"\n"
" leaq 352(%rsp), %rsp\n"
"\n"
" jmp __afl_return\n"
"\n"
".AFL_VARS:\n"
"\n"
#ifdef __APPLE__
" .comm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY
" .comm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */
" .comm __afl_fork_pid, 4\n"
" .comm __afl_temp, 4\n"
" .comm __afl_setup_failure, 1\n"
#else
" .lcomm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY
" .lcomm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */
" .lcomm __afl_fork_pid, 4\n"
" .lcomm __afl_temp, 4\n"
" .lcomm __afl_setup_failure, 1\n"
#endif /* ^__APPLE__ */
" .comm __afl_global_area_ptr, 8, 8\n"
"\n"
".AFL_SHM_ENV:\n"
" .asciz \"" SHM_ENV_VAR "\"\n"
"\n"
"/* --- END --- */\n"
"\n";
#endif /* !_HAVE_AFL_AS_H */

View File

@ -21,7 +21,7 @@ TL;DR:
The code in this directory allows to instrument programs for AFL++ using true The code in this directory allows to instrument programs for AFL++ using true
compiler-level instrumentation, instead of the more crude assembly-level compiler-level instrumentation, instead of the more crude assembly-level
rewriting approach taken by afl-gcc and afl-clang. This has several interesting rewriting approach taken by obsolete afl-gcc and afl-clang. This has several interesting
properties: properties:
- The compiler can make many optimizations that are hard to pull off when - The compiler can make many optimizations that are hard to pull off when
@ -40,10 +40,6 @@ properties:
will *not* work with LLVM (see [README.llvm.md](README.llvm.md) for an will *not* work with LLVM (see [README.llvm.md](README.llvm.md) for an
alternative). alternative).
Once this implementation is shown to be sufficiently robust and portable, it
will probably replace afl-gcc. For now, it can be built separately and co-exists
with the original code.
The idea and much of the implementation comes from Laszlo Szekeres. The idea and much of the implementation comes from Laszlo Szekeres.
## 2) How to use ## 2) How to use
@ -77,7 +73,7 @@ standard operating mode of AFL++, e.g.:
Note: We also used `CXX` to set the C++ compiler to `afl-g++-fast` for C++ code. Note: We also used `CXX` to set the C++ compiler to `afl-g++-fast` for C++ code.
The tool honors roughly the same environmental variables as `afl-gcc` (see The tool honors some environmental variables of `afl-clang-fast` (see
[docs/env_variables.md](../docs/env_variables.md). This includes [docs/env_variables.md](../docs/env_variables.md). This includes
`AFL_INST_RATIO`, `AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`. `AFL_INST_RATIO`, `AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`.

View File

@ -3,7 +3,7 @@
This file describes two different mechanisms to selectively instrument only This file describes two different mechanisms to selectively instrument only
specific parts in the target. specific parts in the target.
Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc. Both mechanisms work for LLVM and GCC_PLUGIN.
## 1) Description and purpose ## 1) Description and purpose

View File

@ -11,7 +11,7 @@ For the GCC-based instrumentation, see
The code in this directory allows you to instrument programs for AFL++ using The code in this directory allows you to instrument programs for AFL++ using
true compiler-level instrumentation, instead of the more crude assembly-level true compiler-level instrumentation, instead of the more crude assembly-level
rewriting approach taken by afl-gcc and afl-clang. This has several interesting rewriting approach taken by obsolete afl-gcc and afl-clang. This has several interesting
properties: properties:
- The compiler can make many optimizations that are hard to pull off when - The compiler can make many optimizations that are hard to pull off when
@ -32,10 +32,6 @@ properties:
will *not* work with GCC (see ../gcc_plugin/ for an alternative once it is will *not* work with GCC (see ../gcc_plugin/ for an alternative once it is
available). available).
Once this implementation is shown to be sufficiently robust and portable, it
will probably replace afl-clang. For now, it can be built separately and
co-exists with the original code.
The idea and much of the initial implementation came from Laszlo Szekeres. The idea and much of the initial implementation came from Laszlo Szekeres.
## 2a) How to use this - short ## 2a) How to use this - short
@ -105,7 +101,7 @@ 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 either setting `AFL_CC_COMPILER=LLVM` or pass the parameter `--afl-llvm` via
CFLAGS/CXXFLAGS/CPPFLAGS. CFLAGS/CXXFLAGS/CPPFLAGS.
The tool honors roughly the same environmental variables as afl-gcc (see The tool supports a lot of environmental variables(see
[docs/env_variables.md](../docs/env_variables.md)). This includes [docs/env_variables.md](../docs/env_variables.md)). This includes
`AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`. However, `AFL_INST_RATIO` `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 is not honored as it does not serve a good purpose with the more effective
@ -255,10 +251,6 @@ low cost (one instruction per edge).
(The alternative of saturated counters has been tested also and proved to be (The alternative of saturated counters has been tested also and proved to be
inferior in terms of path discovery.) inferior in terms of path discovery.)
This is implemented in afl-gcc and afl-gcc-fast, however, for llvm_mode this is
optional if multithread safe counters are selected or the llvm version is below
9 - as there are severe performance costs in these cases.
If you want to enable this for llvm versions below 9 or thread safe counters, If you want to enable this for llvm versions below 9 or thread safe counters,
then set then set

View File

@ -57,8 +57,8 @@ libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtif
afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO
afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
AUTODICTIONARY: 11 strings found AUTODICTIONARY: 11 strings found
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). [+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-clang-fast CLASSIC) (non-hardened mode).
``` s```
## Getting LLVM 12+ ## Getting LLVM 12+
@ -90,7 +90,7 @@ sudo make install
## How to use afl-clang-lto ## How to use afl-clang-lto
Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc. Just use afl-clang-lto like you did with afl-clang-fast.
Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -> Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST ->
[README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov [README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov

View File

@ -124,7 +124,6 @@ will keep working normally when compiled with a tool other than afl-clang-fast/
afl-clang-lto/afl-gcc-fast. afl-clang-lto/afl-gcc-fast.
Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
(afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
and you should be all set! and you should be all set!
## 4) Persistent mode ## 4) Persistent mode

View File

@ -5,9 +5,6 @@
Written by Laszlo Szekeres <lszekeres@google.com> and Written by Laszlo Szekeres <lszekeres@google.com> and
Michal Zalewski Michal Zalewski
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
from afl-as.c are Michal's fault.
Copyright 2015, 2016 Google Inc. All rights reserved. Copyright 2015, 2016 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved. Copyright 2019-2024 AFLplusplus Project. All rights reserved.
@ -17,10 +14,6 @@
https://www.apache.org/licenses/LICENSE-2.0 https://www.apache.org/licenses/LICENSE-2.0
This library is plugged into LLVM when invoking clang through afl-clang-fast.
It tells the compiler to add code roughly equivalent to the bits discussed
in ../afl-as.h.
*/ */
#define AFL_LLVM_PASS #define AFL_LLVM_PASS

View File

@ -6,9 +6,6 @@
Adrian Herrera <adrian.herrera@anu.edu.au>, Adrian Herrera <adrian.herrera@anu.edu.au>,
Michal Zalewski Michal Zalewski
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
from afl-as.c are Michal's fault.
NGRAM previous location coverage comes from Adrian Herrera. NGRAM previous location coverage comes from Adrian Herrera.
Copyright 2015, 2016 Google Inc. All rights reserved. Copyright 2015, 2016 Google Inc. All rights reserved.
@ -20,10 +17,6 @@
https://www.apache.org/licenses/LICENSE-2.0 https://www.apache.org/licenses/LICENSE-2.0
This library is plugged into LLVM when invoking clang through afl-clang-fast.
It tells the compiler to add code roughly equivalent to the bits discussed
in ../afl-as.h.
*/ */
#define AFL_LLVM_PASS #define AFL_LLVM_PASS

View File

@ -1,671 +0,0 @@
/*
american fuzzy lop++ - wrapper for GNU as
-----------------------------------------
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2024 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:
https://www.apache.org/licenses/LICENSE-2.0
The sole purpose of this wrapper is to preprocess assembly files generated
by GCC / clang and inject the instrumentation bits included from afl-as.h. It
is automatically invoked by the toolchain when compiling programs using
afl-gcc / afl-clang.
Note that it's an explicit non-goal to instrument hand-written assembly,
be it in separate .s files or in __asm__ blocks. The only aspiration this
utility has right now is to be able to skip them gracefully and allow the
compilation process to continue.
That said, see utils/clang_asm_normalize/ for a solution that may
allow clang users to make things work even with hand-crafted assembly. Just
note that there is no equivalent for GCC.
*/
#define AFL_MAIN
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "afl-as.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
static u8 **as_params; /* Parameters passed to the real 'as' */
static u8 *input_file; /* Originally specified input file */
static u8 *modified_file; /* Instrumented file for the real 'as' */
static u8 be_quiet, /* Quiet mode (no stderr output) */
clang_mode, /* Running in clang mode? */
pass_thru, /* Just pass data through? */
just_version, /* Just show version? */
sanitizer; /* Using ASAN / MSAN */
static u32 inst_ratio = 100, /* Instrumentation probability (%) */
as_par_cnt = 1; /* Number of params to 'as' */
/* If we don't find --32 or --64 in the command line, default to
instrumentation for whichever mode we were compiled with. This is not
perfect, but should do the trick for almost all use cases. */
#ifdef WORD_SIZE_64
static u8 use_64bit = 1;
#else
static u8 use_64bit = 0;
#ifdef __APPLE__
#error "Sorry, 32-bit Apple platforms are not supported."
#endif /* __APPLE__ */
#endif /* ^WORD_SIZE_64 */
/* Examine and modify parameters to pass to 'as'. Note that the file name
is always the last parameter passed by GCC, so we exploit this property
to keep the code simple. */
static void edit_params(int argc, char **argv) {
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
u32 i, input_index;
#ifdef __APPLE__
u8 use_clang_as = 0;
/* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work
with the code generated by newer versions of clang that are hand-built
by the user. See the thread here: https://goo.gl/HBWDtn.
To work around this, when using clang and running without AFL_AS
specified, we will actually call 'clang -c' instead of 'as -q' to
compile the assembly file.
The tools aren't cmdline-compatible, but at least for now, we can
seemingly get away with this by making only very minor tweaks. Thanks
to Nico Weber for the idea. */
if (clang_mode && !afl_as) {
use_clang_as = 1;
afl_as = getenv("AFL_CC");
if (!afl_as) afl_as = getenv("AFL_CXX");
if (!afl_as) afl_as = "clang";
}
#endif /* __APPLE__ */
/* Although this is not documented, GCC also uses TEMP and TMP when TMPDIR
is not set. We need to check these non-standard variables to properly
handle the pass_thru logic later on. */
if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; }
as_params = ck_alloc((argc + 32) * sizeof(u8 *));
if (unlikely((INT_MAX - 32) < argc || !as_params)) {
FATAL("Too many parameters passed to as");
}
as_params[0] = afl_as ? afl_as : (u8 *)"as";
as_params[argc] = 0;
/* Find the input file. It's usually located near the end.
Assume there won't be any arguments referring to files after the input
file, e.g. as input.s -o output.o */
for (input_index = argc - 1; input_index > 0; input_index--) {
input_file = argv[input_index];
/* Clang may add debug arguments after the input file. */
if (strncmp(input_file, "-g", 2)) break;
}
if (input_index == 0)
FATAL("Could not find input file (not called through afl-gcc?)");
for (i = 1; (s32)i < argc; i++) {
if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) {
use_64bit = 1;
} else if (!strcmp(argv[i], "--32")) {
use_64bit = 0;
}
#ifdef __APPLE__
/* The Apple case is a bit different... */
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
if (!strcmp(argv[i + 1], "x86_64"))
use_64bit = 1;
else if (!strcmp(argv[i + 1], "i386"))
FATAL("Sorry, 32-bit Apple platforms are not supported.");
}
/* Strip options that set the preference for a particular upstream
assembler in Xcode. */
if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
continue;
#endif /* __APPLE__ */
as_params[as_par_cnt++] = argv[i];
}
#ifdef __APPLE__
/* When calling clang as the upstream assembler, append -c -x assembler
and hope for the best. */
if (use_clang_as) {
as_params[as_par_cnt++] = "-c";
as_params[as_par_cnt++] = "-x";
as_params[as_par_cnt++] = "assembler";
}
#endif /* __APPLE__ */
if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) {
just_version = 1;
modified_file = input_file;
goto wrap_things_up;
}
if (input_file[1]) {
FATAL("Incorrect use (not called through afl-gcc?)");
} else {
input_file = NULL;
}
} else {
/* Check if this looks like a standard invocation as a part of an attempt
to compile a program, rather than using gcc on an ad-hoc .s file in
a format we may not understand. This works around an issue compiling
NSS. */
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) &&
strncmp(input_file, "/tmp/", 5) &&
getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) {
pass_thru = 1;
} else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
unsetenv("AFL_AS_FORCE_INSTRUMENT");
}
}
modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
(u32)time(NULL), (u32)random());
wrap_things_up:
as_params[as_par_cnt++] = modified_file;
as_params[as_par_cnt] = NULL;
}
/* Process input file, generate modified_file. Insert instrumentation in all
the appropriate places. */
static void add_instrumentation(void) {
static u8 line[MAX_LINE];
FILE *inf;
FILE *outf;
s32 outfd;
u32 ins_lines = 0;
u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0, skip_intel = 0,
skip_app = 0, instrument_next = 0;
#ifdef __APPLE__
u8 *colon_pos;
#endif /* __APPLE__ */
if (input_file) {
inf = fopen(input_file, "r");
if (!inf) { PFATAL("Unable to read '%s'", input_file); }
} else {
inf = stdin;
}
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, DEFAULT_PERMISSION);
if (outfd < 0) { PFATAL("Unable to write to '%s'", modified_file); }
outf = fdopen(outfd, "w");
if (!outf) { PFATAL("fdopen() failed"); }
while (fgets(line, MAX_LINE, inf)) {
/* In some cases, we want to defer writing the instrumentation trampoline
until after all the labels, macros, comments, etc. If we're in this
mode, and if the line starts with a tab followed by a character, dump
the trampoline now. */
if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
instrument_next && line[0] == '\t' && isalpha(line[1])) {
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
R(MAP_SIZE));
instrument_next = 0;
ins_lines++;
}
/* Output the actual line, call it a day in pass-thru mode. */
fputs(line, outf);
if (pass_thru) { continue; }
/* All right, this is where the actual fun begins. For one, we only want to
instrument the .text section. So, let's keep track of that in processed
files - and let's set instr_ok accordingly. */
if (line[0] == '\t' && line[1] == '.') {
/* OpenBSD puts jump tables directly inline with the code, which is
a bit annoying. They use a specific format of p2align directives
around them, so we use that as a signal. */
if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) &&
isdigit(line[10]) && line[11] == '\n') {
skip_next_label = 1;
}
if (!strncmp(line + 2, "text\n", 5) ||
!strncmp(line + 2, "section\t.text", 13) ||
!strncmp(line + 2, "section\t__TEXT,__text", 21) ||
!strncmp(line + 2, "section __TEXT,__text", 21)) {
instr_ok = 1;
continue;
}
if (!strncmp(line + 2, "section\t", 8) ||
!strncmp(line + 2, "section ", 8) || !strncmp(line + 2, "bss\n", 4) ||
!strncmp(line + 2, "data\n", 5)) {
instr_ok = 0;
continue;
}
}
/* Detect off-flavor assembly (rare, happens in gdb). When this is
encountered, we set skip_csect until the opposite directive is
seen, and we do not instrument. */
if (strstr(line, ".code")) {
if (strstr(line, ".code32")) { skip_csect = use_64bit; }
if (strstr(line, ".code64")) { skip_csect = !use_64bit; }
}
/* Detect syntax changes, as could happen with hand-written assembly.
Skip Intel blocks, resume instrumentation when back to AT&T. */
if (strstr(line, ".intel_syntax")) { skip_intel = 1; }
if (strstr(line, ".att_syntax")) { skip_intel = 0; }
/* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */
if (line[0] == '#' || line[1] == '#') {
if (strstr(line, "#APP")) { skip_app = 1; }
if (strstr(line, "#NO_APP")) { skip_app = 0; }
}
/* If we're in the right mood for instrumenting, check for function
names or conditional labels. This is a bit messy, but in essence,
we want to catch:
^main: - function entry point (always instrumented)
^.L0: - GCC branch label
^.LBB0_0: - clang branch label (but only in clang mode)
^\tjnz foo - conditional branches
...but not:
^# BB#0: - clang comments
^ # BB#0: - ditto
^.Ltmp0: - clang non-branch labels
^.LC0 - GCC non-branch labels
^.LBB0_0: - ditto (when in GCC mode)
^\tjmp foo - non-conditional jumps
Additionally, clang and GCC on MacOS X follow a different convention
with no leading dots on labels, hence the weird maze of #ifdefs
later on.
*/
if (skip_intel || skip_app || skip_csect || !instr_ok || line[0] == '#' ||
line[0] == ' ') {
continue;
}
/* Conditional branch instruction (jnz, etc). We append the instrumentation
right after the branch (to instrument the not-taken path) and at the
branch destination label (handled later on). */
if (line[0] == '\t') {
if (line[1] == 'j' && line[2] != 'm' && R(100) < (long)inst_ratio) {
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
R(MAP_SIZE));
ins_lines++;
}
continue;
}
/* Label of some sort. This may be a branch destination, but we need to
read carefully and account for several different formatting
conventions. */
#ifdef __APPLE__
/* Apple: L<whatever><digit>: */
if ((colon_pos = strstr(line, ":"))) {
if (line[0] == 'L' && isdigit(*(colon_pos - 1))) {
#else
/* Everybody else: .L<whatever>: */
if (strstr(line, ":")) {
if (line[0] == '.') {
#endif /* __APPLE__ */
/* .L0: or LBB0_0: style jump destination */
#ifdef __APPLE__
/* Apple: L<num> / LBB<num> */
if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) &&
R(100) < (long)inst_ratio) {
#else
/* Apple: .L<num> / .LBB<num> */
if ((isdigit(line[2]) ||
(clang_mode && !strncmp(line + 1, "LBB", 3))) &&
R(100) < (long)inst_ratio) {
#endif /* __APPLE__ */
/* An optimization is possible here by adding the code only if the
label is mentioned in the code in contexts other than call / jmp.
That said, this complicates the code by requiring two-pass
processing (messy with stdin), and results in a speed gain
typically under 10%, because compilers are generally pretty good
about not generating spurious intra-function jumps.
We use deferred output chiefly to avoid disrupting
.Lfunc_begin0-style exception handling calculations (a problem on
MacOS X). */
if (!skip_next_label) {
instrument_next = 1;
} else {
skip_next_label = 0;
}
}
} else {
/* Function label (always instrumented, deferred mode). */
instrument_next = 1;
}
}
}
if (ins_lines) { fputs(use_64bit ? main_payload_64 : main_payload_32, outf); }
if (input_file) { fclose(inf); }
fclose(outf);
if (!be_quiet) {
if (!ins_lines) {
WARNF("No instrumentation targets found%s.",
pass_thru ? " (pass-thru mode)" : "");
} else {
char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "",
getenv("AFL_USE_LSAN") ? ", LSAN" : "");
OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines,
use_64bit ? "64" : "32", modeline, inst_ratio);
}
}
}
/* Main entry point */
int main(int argc, char **argv) {
s32 pid;
u32 rand_seed, i, j;
int status;
u8 *inst_ratio_str = getenv("AFL_INST_RATIO");
struct timeval tv;
struct timezone tz;
clang_mode = !!getenv(CLANG_ENV_VAR);
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-as" VERSION cRST " by Michal Zalewski\n");
} else {
be_quiet = 1;
}
if (argc < 2 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
fprintf(
stdout,
"afl-as" VERSION
" by Michal Zalewski\n"
"\n%s [-h]\n\n"
"This is a helper application for afl-fuzz. It is a wrapper around GNU "
"'as',\n"
"executed by the toolchain whenever using afl-gcc or afl-clang. You "
"probably\n"
"don't want to run this program directly.\n\n"
"Rarely, when dealing with extremely complex projects, it may be "
"advisable\n"
"to set AFL_INST_RATIO to a value less than 100 in order to reduce "
"the\n"
"odds of instrumenting every discovered branch.\n\n"
"Environment variables used:\n"
"AFL_AS: path to assembler to use for instrumented files\n"
"AFL_CC: fall back path to assembler\n"
"AFL_CXX: fall back path to assembler\n"
"TMPDIR: directory to use for temporary files\n"
"TEMP: fall back path to directory for temporary files\n"
"TMP: fall back path to directory for temporary files\n"
"AFL_INST_RATIO: user specified instrumentation ratio\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"
"AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n"
" used in the instrumentation summary message\n",
argv[0]);
exit(1);
}
gettimeofday(&tv, &tz);
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
// in fast systems where pids can repeat in the same seconds we need this
for (i = 1; (s32)i < argc; i++)
for (j = 0; j < strlen(argv[i]); j++)
rand_seed += argv[i][j];
srandom(rand_seed);
edit_params(argc, argv);
if (inst_ratio_str) {
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100) {
FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)");
}
}
if (getenv(AS_LOOP_ENV_VAR)) {
FATAL("Endless loop when calling 'as' (remove '.' from your PATH)");
}
setenv(AS_LOOP_ENV_VAR, "1", 1);
/* When compiling with ASAN, we don't have a particularly elegant way to skip
ASAN-specific branches. But we can probabilistically compensate for
that... */
if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) {
sanitizer = 1;
if (!getenv("AFL_INST_RATIO")) { inst_ratio /= 3; }
}
if (!just_version) { add_instrumentation(); }
if (!(pid = fork())) {
execvp(as_params[0], (char **)as_params);
FATAL("Oops, failed to execute '%s' - check your PATH", as_params[0]);
}
if (pid < 0) { PFATAL("fork() failed"); }
if (waitpid(pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
if (!getenv("AFL_KEEP_ASSEMBLY")) { unlink(modified_file); }
exit(WEXITSTATUS(status));
}

View File

@ -602,7 +602,6 @@ void compiler_mode_by_callname(aflcc_state_t *aflcc) {
if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) { if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
/* afl-clang-fast is always created there by makefile /* afl-clang-fast is always created there by makefile
just like afl-clang, burdened with special purposes:
- If llvm-config is not available (i.e. LLVM_MAJOR is 0), - If llvm-config is not available (i.e. LLVM_MAJOR is 0),
or too old, it falls back to LLVM-NATIVE mode and let or too old, it falls back to LLVM-NATIVE mode and let
the actual compiler complain if doesn't work. the actual compiler complain if doesn't work.
@ -1220,11 +1219,8 @@ void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) {
switch (aflcc->compiler_mode) { switch (aflcc->compiler_mode) {
case GCC: case GCC:
if (!aflcc->have_gcc) FATAL("afl-gcc is not available on your platform!");
break; break;
case CLANG: case CLANG:
if (!aflcc->have_clang)
FATAL("afl-clang is not available on your platform!");
break; break;
case LLVM: case LLVM:
if (!aflcc->have_llvm) if (!aflcc->have_llvm)
@ -1564,7 +1560,6 @@ void add_defs_selective_instr(aflcc_state_t *aflcc) {
/* /*
Macro defs for persistent mode. As documented in Macro defs for persistent mode. As documented in
instrumentation/README.persistent_mode.md, deferred forkserver initialization instrumentation/README.persistent_mode.md, deferred forkserver initialization
and persistent mode are not available in afl-gcc and afl-clang.
*/ */
void add_defs_persistent_mode(aflcc_state_t *aflcc) { void add_defs_persistent_mode(aflcc_state_t *aflcc) {
@ -2845,10 +2840,7 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
" yes\n" " yes\n"
" [GCC_PLUGIN] gcc plugin: %s%s\n" " [GCC_PLUGIN] gcc plugin: %s%s\n"
" CLASSIC DEFAULT no yes no no no " " CLASSIC DEFAULT no yes no no no "
"yes\n" "yes\n\n",
" [GCC/CLANG] simple gcc/clang: %s%s\n"
" CLASSIC DEFAULT no no no no no "
"no\n\n",
aflcc->have_llvm ? "AVAILABLE " : "unavailable!", aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
aflcc->compiler_mode == LLVM ? " [SELECTED]" : "", aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
aflcc->have_llvm ? "AVAILABLE " : "unavailable!", aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
@ -2856,15 +2848,7 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
aflcc->have_lto ? "AVAILABLE" : "unavailable!", aflcc->have_lto ? "AVAILABLE" : "unavailable!",
aflcc->compiler_mode == LTO ? " [SELECTED]" : "", aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!", aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "", aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "");
aflcc->have_gcc && aflcc->have_clang
? "AVAILABLE"
: (aflcc->have_gcc
? "GCC ONLY "
: (aflcc->have_clang ? "CLANG ONLY" : "unavailable!")),
(aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)
? " [SELECTED]"
: "");
SAYF( SAYF(
"Modes:\n" "Modes:\n"
@ -3554,10 +3538,12 @@ int main(int argc, char **argv, char **envp) {
maybe_usage(aflcc, argc, argv); maybe_usage(aflcc, argc, argv);
if ((aflcc->compiler_mode == CLANG || aflcc->compiler_mode == GCC) && if (aflcc->instrument_mode == INSTRUMENT_GCC || aflcc->instrument_mode ==
aflcc->need_aflpplib) { INSTRUMENT_CLANG) {
FATAL("afl-gcc/afl-clang cannot be used together with -fsanitize=fuzzer"); FATAL(
"afl-gcc/afl-clang are obsolete and has been removed. Use "
"afl-clang-fast/afl-gcc-fast for instrumentation instead.");
} }
@ -3567,9 +3553,12 @@ int main(int argc, char **argv, char **envp) {
edit_params(aflcc, argc, argv, envp); edit_params(aflcc, argc, argv, envp);
if (aflcc->debug) if (aflcc->debug) {
debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params); debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
}
if (aflcc->passthrough) { if (aflcc->passthrough) {
argv[0] = aflcc->cc_params[0]; argv[0] = aflcc->cc_params[0];

View File

@ -552,7 +552,7 @@ void nyx_load_target_hash(afl_forkserver_t *fsrv) {
In essence, the instrumentation allows us to skip execve(), and just keep In essence, the instrumentation allows us to skip execve(), and just keep
cloning a stopped child. So, we just execute once, and then send commands cloning a stopped child. So, we just execute once, and then send commands
through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ through a pipe. The other part of this logic is in afl-compilter-rt.o */
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) { volatile u8 *stop_soon_p, u8 debug_child_output) {

View File

@ -3096,9 +3096,9 @@ void check_binary(afl_state_t *afl, u8 *fname) {
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST SAYF("\n" cLRD "[-] " cRST
"This program appears to be instrumented with afl-gcc, but is being " "This program appears to be instrumented with AFL++ compilers, but is "
"run in\n" "being run\n"
" QEMU mode (-Q). This is probably not what you " " in QEMU mode (-Q). This is probably not what you "
"want -\n" "want -\n"
" this setup will be slow and offer no practical benefits.\n"); " this setup will be slow and offer no practical benefits.\n");

View File

@ -4,60 +4,58 @@
OS=$(uname -s) OS=$(uname -s)
AFL_GCC=afl-gcc AFL_COMPILER=afl-clang-fast
$ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin" $ECHO "$BLUE[*] Testing: ${AFL_COMPILER}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "i386" && { test -e ../${AFL_COMPILER} -a -e ../afl-showmap -a -e ../afl-fuzz && {
test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && { ../${AFL_COMPILER} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
../${AFL_GCC} -v 2>&1 | grep -qi "gcc version" && { AFL_HARDEN=1 ../${AFL_COMPILER} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
test -e test-instr.plain && { test -e test-instr.plain && {
$ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded" $ECHO "$GREEN[+] ${AFL_COMPILER} compilation succeeded"
echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1 echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1 AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
test -e test-instr.plain.0 -a -e test-instr.plain.1 && { test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && { diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
$ECHO "$RED[!] ${AFL_GCC} instrumentation should be different on different input but is not" $ECHO "$RED[!] ${AFL_COMPILER} instrumentation should be different on different input but is not"
CODE=1 CODE=1
} || { } || {
$ECHO "$GREEN[+] ${AFL_GCC} instrumentation present and working correctly" $ECHO "$GREEN[+] ${AFL_COMPILER} instrumentation present and working correctly"
} }
} || { } || {
$ECHO "$RED[!] ${AFL_GCC} instrumentation failed" $ECHO "$RED[!] ${AFL_COMPILER} instrumentation failed"
CODE=1 CODE=1
} }
rm -f test-instr.plain.0 test-instr.plain.1 rm -f test-instr.plain.0 test-instr.plain.1
SKIP= SKIP=
TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'` TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && { test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && {
$ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine" $ECHO "$GREEN[+] ${AFL_COMPILER} run reported $TUPLES instrumented locations which is fine"
} || { } || {
$ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES" $ECHO "$RED[!] ${AFL_COMPILER} instrumentation produces weird numbers: $TUPLES"
CODE=1 CODE=1
} }
test "$TUPLES" -lt 3 && SKIP=1 test "$TUPLES" -lt 3 && SKIP=1
true # this is needed because of the test above true # this is needed because of the test above
} || { } || {
$ECHO "$RED[!] ${AFL_GCC} failed" $ECHO "$RED[!] ${AFL_COMPILER} failed"
echo CUT------------------------------------------------------------------CUT echo CUT------------------------------------------------------------------CUT
uname -a uname -a
../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c ../${AFL_COMPILER} -o test-instr.plain -O0 ../test-instr.c
echo CUT------------------------------------------------------------------CUT echo CUT------------------------------------------------------------------CUT
CODE=1 CODE=1
} }
test -e test-compcov.harden && { test -e test-compcov.harden && {
nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && { nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
$ECHO "$GREEN[+] ${AFL_GCC} hardened mode succeeded and is working" $ECHO "$GREEN[+] ${AFL_COMPILER} hardened mode succeeded and is working"
} || { } || {
$ECHO "$RED[!] ${AFL_GCC} hardened mode is not hardened" $ECHO "$RED[!] ${AFL_COMPILER} hardened mode is not hardened"
env | grep -E 'AFL|PATH|LLVM' env | grep -E 'AFL|PATH|LLVM'
AFL_DEBUG=1 AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c AFL_DEBUG=1 AFL_HARDEN=1 ../${AFL_COMPILER} -o test-compcov.harden test-compcov.c
nm test-compcov.harden nm test-compcov.harden
CODE=1 CODE=1
} }
rm -f test-compcov.harden rm -f test-compcov.harden
} || { } || {
$ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed" $ECHO "$RED[!] ${AFL_COMPILER} hardened mode compilation failed"
CODE=1 CODE=1
} }
# now we want to be sure that afl-fuzz is working # now we want to be sure that afl-fuzz is working
@ -69,17 +67,17 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
mkdir -p in mkdir -p in
echo 0 > in/in echo 0 > in/in
test -z "$SKIP" && { test -z "$SKIP" && {
$ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC}, this will take approx 10 seconds" $ECHO "$GREY[*] running afl-fuzz for ${AFL_COMPILER}, this will take approx 10 seconds"
{ {
../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1 ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1
} >>errors 2>&1 } >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_GCC}" $ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_COMPILER}"
} || { } || {
echo CUT------------------------------------------------------------------CUT echo CUT------------------------------------------------------------------CUT
cat errors cat errors
echo CUT------------------------------------------------------------------CUT echo CUT------------------------------------------------------------------CUT
$ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}" $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_COMPILER}"
CODE=1 CODE=1
} }
} }
@ -124,159 +122,9 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
unset AFL_QUIET unset AFL_QUIET
} }
rm -f test-instr.plain rm -f test-instr.plain
} || {
$ECHO "$YELLOW[-] afl-gcc executes clang, cannot test!"
INCOMPLETE=1
}
} || { } || {
$ECHO "$YELLOW[-] afl is not compiled, cannot test" $ECHO "$YELLOW[-] afl is not compiled, cannot test"
INCOMPLETE=1 INCOMPLETE=1
} }
AFL_CLANG=afl-clang
$ECHO "$BLUE[*] Testing: ${AFL_CLANG}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
SKIP=
test -e ../${AFL_CLANG} -a -e ../afl-showmap -a -e ../afl-fuzz && {
../${AFL_CLANG} -v 2>&1 | grep -qi "clang version" && {
../${AFL_CLANG} -O0 -o test-instr.plain ../test-instr.c > /dev/null 2>&1
AFL_HARDEN=1 ../${AFL_CLANG} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
test -e test-instr.plain && {
$ECHO "$GREEN[+] ${AFL_CLANG} compilation succeeded"
echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
$ECHO "$RED[!] ${AFL_CLANG} instrumentation should be different on different input but is not"
CODE=1
} || {
$ECHO "$GREEN[+] ${AFL_CLANG} instrumentation present and working correctly"
}
} || {
$ECHO "$RED[!] ${AFL_CLANG} instrumentation failed"
CODE=1
}
rm -f test-instr.plain.0 test-instr.plain.1
TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && {
$ECHO "$GREEN[+] ${AFL_CLANG} run reported $TUPLES instrumented locations which is fine"
} || {
$ECHO "$RED[!] ${AFL_CLANG} instrumentation produces weird numbers: $TUPLES"
CODE=1
}
test "$TUPLES" -lt 3 && SKIP=1
true # this is needed because of the test above
} || {
$ECHO "$RED[!] ${AFL_CLANG} failed"
echo CUT------------------------------------------------------------------CUT
uname -a
../${AFL_CLANG} -o test-instr.plain ../test-instr.c
echo CUT------------------------------------------------------------------CUT
CODE=1
}
test -e test-compcov.harden && {
nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
$ECHO "$GREEN[+] ${AFL_CLANG} hardened mode succeeded and is working"
} || {
$ECHO "$RED[!] ${AFL_CLANG} hardened mode is not hardened"
CODE=1
}
rm -f test-compcov.harden
} || {
$ECHO "$RED[!] ${AFL_CLANG} hardened mode compilation failed"
CODE=1
}
# now we want to be sure that afl-fuzz is working
# make sure crash reporter is disabled on Mac OS X
(test "$OS" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
$ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
true
}) || {
mkdir -p in
echo 0 > in/in
test -z "$SKIP" && {
$ECHO "$GREY[*] running afl-fuzz for ${AFL_CLANG}, this will take approx 10 seconds"
{
../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_CLANG}"
} || {
echo CUT------------------------------------------------------------------CUT
cat errors
echo CUT------------------------------------------------------------------CUT
$ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_CLANG}"
CODE=1
}
}
echo 000000000000000000000000 > in/in2
echo AAA > in/in2
test "$OS" = "Darwin" && {
$ECHO "$GREY[*] afl-cmin not available on macOS, cannot test afl-cmin"
} || {
mkdir -p in2
../afl-cmin -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null 2>&1 # why is afl-forkserver writing to stderr?
CNT=`ls in2/* 2>/dev/null | wc -l`
case "$CNT" in
*2) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
\ *1|1) { # allow leading whitecase for portability
test -s in2/* && $ECHO "$YELLOW[?] afl-cmin did minimize to one testcase. This can be a bug or due compiler optimization."
test -s in2/* || {
$ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
CODE=1
}
}
;;
*) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)"
CODE=1
;;
esac
rm -f in2/in*
}
export AFL_QUIET=1
if command -v bash >/dev/null ; then {
../afl-cmin.bash -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null
CNT=`ls in2/* 2>/dev/null | wc -l`
case "$CNT" in
*2) $ECHO "$GREEN[+] afl-cmin.bash correctly minimized the number of testcases" ;;
\ *1|1) { # allow leading whitecase for portability
test -s in2/* && $ECHO "$YELLOW[?] afl-cmin.bash did minimize to one testcase. This can be a bug or due compiler optimization."
test -s in2/* || {
$ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
CODE=1
}
}
;;
*) $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)"
CODE=1
;;
esac
} else {
$ECHO "$GREY[*] no bash available, cannot test afl-cmin.bash"
}
fi
../afl-tmin -m ${MEM_LIMIT} -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
SIZE=`ls -l in2/in2 2>/dev/null | awk '{print$5}'`
test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
test "$SIZE" = 1 || {
$ECHO "$RED[!] afl-tmin did incorrectly minimize the testcase to $SIZE"
CODE=1
}
rm -rf in out errors in2
unset AFL_QUIET
}
rm -f test-instr.plain
} || {
$ECHO "$YELLOW[-] afl-clang executes gcc, cannot test"
INCOMPLETE=1
}
} || {
$ECHO "$YELLOW[-] afl is not compiled, cannot test"
INCOMPLETE=1
}
} || {
$ECHO "$GREY[*] not an intel platform, skipped tests of afl-gcc"
#this is not incomplete as this feature doesnt exist, so all good
AFL_TEST_COUNT=$((AFL_TEST_COUNT-1))
}
. ./test-post.sh . ./test-post.sh

View File

@ -11,21 +11,13 @@ test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUS
test -e ../afl-clang-fast && { test -e ../afl-clang-fast && {
../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
} || { } || {
test -e ../afl-gcc-fast && { ../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
} || {
../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
}
} }
# Compile the vulnerable program for multiple mutators # Compile the vulnerable program for multiple mutators
test -e ../afl-clang-fast && { test -e ../afl-clang-fast && {
../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1 ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
} || { } || {
test -e ../afl-gcc-fast && { ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
} || {
../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
}
} }
# Compile the custom mutator # Compile the custom mutator
cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1

View File

@ -81,7 +81,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
# now for the special gcc_plugin things # now for the special gcc_plugin things
echo foobar.c > instrumentlist.txt echo foobar.c > instrumentlist.txt
AFL_GCC_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1 AFL_COMPILER_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1
test -x test-compcov && test_compcov_binary_functionality ./test-compcov && { test -x test-compcov && test_compcov_binary_functionality ./test-compcov && {
echo 1 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o - -r -- ./test-compcov 2>&1 | grep -q "Captured 0 tuples" && { echo 1 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o - -r -- ./test-compcov 2>&1 | grep -q "Captured 0 tuples" && {
$ECHO "$GREEN[+] gcc_plugin instrumentlist feature works correctly" $ECHO "$GREEN[+] gcc_plugin instrumentlist feature works correctly"

View File

@ -26,7 +26,7 @@ unset AFL_USE_ASAN
unset AFL_USE_MSAN unset AFL_USE_MSAN
unset AFL_CC unset AFL_CC
unset AFL_PRELOAD unset AFL_PRELOAD
unset AFL_GCC_INSTRUMENT_FILE unset AFL_COMPILER_INSTRUMENT_FILE
unset AFL_LLVM_INSTRUMENT_FILE unset AFL_LLVM_INSTRUMENT_FILE
unset AFL_LLVM_INSTRIM unset AFL_LLVM_INSTRIM
unset AFL_LLVM_LAF_SPLIT_SWITCHES unset AFL_LLVM_LAF_SPLIT_SWITCHES
@ -37,15 +37,6 @@ unset AFL_LLVM_LAF_SPLIT_COMPARES
test -e /usr/local/bin/opt && { test -e /usr/local/bin/opt && {
export PATH=/usr/local/bin:${PATH} export PATH=/usr/local/bin:${PATH}
} }
# on MacOS X we prefer afl-clang over afl-gcc, because
# afl-gcc does not work there
test `uname -s` = 'Darwin' -o `uname -s` = 'FreeBSD' && {
AFL_GCC=afl-clang
CC=clang
} || {
AFL_GCC=afl-gcc
CC=gcc
}
ECHO="printf %b\\n" ECHO="printf %b\\n"
$ECHO \\101 2>&1 | grep -qE '^A' || { $ECHO \\101 2>&1 | grep -qE '^A' || {
@ -76,30 +67,6 @@ echo
$ECHO "${RESET}${GREY}[*] starting AFL++ performance test framework ..." $ECHO "${RESET}${GREY}[*] starting AFL++ performance test framework ..."
$ECHO "$BLUE[*] Testing: ${AFL_GCC}"
GCC=x
test -e ../${AFL_GCC} -a -e ../afl-fuzz && {
../${AFL_GCC} -o test-instr.plain ../test-instr.c > /dev/null 2>&1
test -e test-instr.plain && {
$ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
mkdir -p in
echo 0 > in/in
$ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC} for 30 seconds"
{
../afl-fuzz -V 30 -s 123 -m ${MEM_LIMIT} -i in -o out-gcc -- ./test-instr.plain
} >>errors 2>&1
test -n "$( ls out-gcc/default/queue/id:000002* 2> /dev/null )" && {
GCC=`grep execs_done out-gcc/default/fuzzer_stats | awk '{print$3}'`
} || {
echo CUT----------------------------------------------------------------
cat errors
echo CUT----------------------------------------------------------------
$ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}"
}
rm -rf in out-gcc errors test-instr.plain
} || $ECHO "$RED[!] ${AFL_GCC} instrumentation failed"
} || $ECHO "$YELLOW[-] afl is not compiled, cannot test"
$ECHO "$BLUE[*] Testing: llvm_mode" $ECHO "$BLUE[*] Testing: llvm_mode"
LLVM=x LLVM=x
test -e ../afl-clang-fast -a -e ../afl-fuzz && { test -e ../afl-clang-fast -a -e ../afl-fuzz && {
@ -232,7 +199,7 @@ test -s $FILE && {
$ECHO "$BLUE[!] qemu_mode: lowest=$LOW_QEMU highest=$HIGH_QEMU last=$LAST_QEMU current=$QEMU" $ECHO "$BLUE[!] qemu_mode: lowest=$LOW_QEMU highest=$HIGH_QEMU last=$LAST_QEMU current=$QEMU"
} || { } || {
$ECHO "$YELLOW[!] First run, just saving data" $ECHO "$YELLOW[!] First run, just saving data"
$ECHO "$BLUE[!] afl-gcc=$GCC llvm_mode=$LLVM gcc_plugin=$GCCP qemu_mode=$QEMU" $ECHO "$BLUE[!] llvm_mode=$LLVM gcc_plugin=$GCCP qemu_mode=$QEMU"
} }
echo "$GCC $LLVM $GCCP $QEMU" >> $FILE echo "$GCC $LLVM $GCCP $QEMU" >> $FILE
$ECHO "$GREY[*] done." $ECHO "$GREY[*] done."

View File

@ -111,14 +111,7 @@ test -n "$TRAVIS_OS_NAME" && {
test -e /usr/local/bin/opt && { test -e /usr/local/bin/opt && {
test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}" test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
} }
# on MacOS X we prefer afl-clang over afl-gcc, because AFL_COMPILER=afl-clang-fast
# afl-gcc does not work there (it is a symlink from clang)
test `uname -s` = 'Darwin' -o `uname -s` = 'FreeBSD' && {
AFL_GCC=afl-clang
} || {
AFL_GCC=afl-gcc
}
command -v gcc >/dev/null 2>&1 || AFL_GCC=afl-clang
SYS=`uname -m` SYS=`uname -m`