mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
4f53803dfe | |||
ed06b3bc9f | |||
3081f589cc | |||
5d08f33a5f | |||
46cbe22feb | |||
6cba007c76 | |||
1461f3a0ee | |||
03d306a97f | |||
0278eb5351 | |||
8e88ef02ad | |||
ad2eaf54ad | |||
a287076ac0 | |||
c352943aa5 | |||
bd3900c084 | |||
48002fe146 | |||
31c8a052a6 | |||
46b87a6d62 | |||
b4208dde94 | |||
4a492d5d8e | |||
945309c316 | |||
41de569353 | |||
7aecf14c07 | |||
7b24f4a329 | |||
ebb919f771 | |||
b43f37456f | |||
701e89bbcd | |||
e3fae3e9b0 | |||
464ec516d5 | |||
3af042d5bf | |||
c1e4b8f7f6 | |||
79deeb46dd | |||
9cf260ca1f | |||
82752fe38d | |||
d11ade56e2 | |||
665d32a0dc | |||
e1bd9fc6ac | |||
2c6f2c970d | |||
0e3157375b | |||
f39cf57eac | |||
e62999c95f | |||
0b22665391 | |||
5777ceaf23 | |||
21916a7f60 | |||
6c83a9ccc1 | |||
bc9fda61a3 | |||
4e0b8beba8 | |||
1448eab8ec | |||
55aec64038 | |||
42fc9acf5b | |||
cdbd86a112 | |||
1aa58a1972 | |||
d0587a3ac4 | |||
d1fd072b79 | |||
c282156451 | |||
a9bda37d18 | |||
577b286508 | |||
009f663e2c | |||
1efb7c8a8b | |||
7f614be3a5 | |||
04d2476b32 | |||
c1d9a4fab9 | |||
8a060a4b68 | |||
a11488b9dc | |||
4cc9232485 | |||
20c46c0ed6 | |||
b3d16f7b8c | |||
c0837409bd | |||
78b7e14c73 | |||
c1e40c5fb7 |
56
GNUmakefile
56
GNUmakefile
@ -19,21 +19,21 @@
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
INCLUDE_PATH = $(PREFIX)/include/afl
|
||||
|
||||
PROGNAME = afl
|
||||
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
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
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)
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
@ -117,7 +117,7 @@ endif
|
||||
COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
|
||||
ifneq "$(COMPILER_TYPE)" ""
|
||||
#$(info gcc is being used)
|
||||
override CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation
|
||||
override CFLAGS_OPT += -Wno-format-truncation
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
@ -325,10 +325,12 @@ ifdef TEST_MMAP
|
||||
endif
|
||||
|
||||
.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
|
||||
@echo
|
||||
@echo
|
||||
@echo
|
||||
@echo
|
||||
@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-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"
|
||||
@ -337,6 +339,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
|
||||
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"
|
||||
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
|
||||
|
||||
.PHONY: llvm
|
||||
@ -463,10 +466,6 @@ endif
|
||||
ready:
|
||||
@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
|
||||
$(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
@ -574,27 +573,27 @@ code-format:
|
||||
|
||||
.PHONY: test_build
|
||||
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..."
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; 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
|
||||
-echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation 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 "[+] All right, the instrumentation of afl-cc seems to be working!"
|
||||
# @echo "[*] Testing the CC wrapper afl-gcc 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 )
|
||||
# @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-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
|
||||
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
# @rm -f test-instr
|
||||
# @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation 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." ) || \
|
||||
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
|
||||
# @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
|
||||
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)."
|
||||
endif
|
||||
|
||||
@ -604,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 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"
|
||||
@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
|
||||
@! 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
|
||||
|
||||
@ -612,7 +612,7 @@ all_done: test_build
|
||||
|
||||
.PHONY: 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-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.gcc_plugin clean
|
||||
-$(MAKE) -C utils/libdislocator clean
|
||||
@ -825,10 +825,10 @@ endif
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
|
||||
@mkdir -m 755 -p $${DESTDIR}$(INCLUDE_PATH)
|
||||
install -m 644 $(HEADERS) $${DESTDIR}$(INCLUDE_PATH)
|
||||
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
||||
@ -836,12 +836,14 @@ endif
|
||||
|
||||
.PHONY: 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}$(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
|
||||
-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
|
||||
-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
|
||||
-cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)
|
||||
-rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null
|
||||
-rmdir $${DESTDIR}$(INCLUDE_PATH) 2>/dev/null
|
||||
-rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null
|
||||
-rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null
|
||||
-rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null
|
||||
|
@ -163,7 +163,7 @@ $(PASSES): instrumentation/afl-gcc-common.h
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
|
@ -69,7 +69,7 @@ endif
|
||||
|
||||
LLVM_STDCXX := gnu++11
|
||||
LLVM_LTO := 0
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-8]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.' && echo 1 || echo 0)
|
||||
# Uncomment to see the values assigned above
|
||||
# $(foreach var,LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
|
||||
@ -163,7 +163,7 @@ endif
|
||||
|
||||
# sanity check.
|
||||
# Are versions of clang --version and llvm-config --version equal?
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([12]?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
|
||||
# I disable this because it does not make sense with what we did before (marc)
|
||||
# We did exactly set these 26 lines above with these values, and it would break
|
||||
@ -508,7 +508,7 @@ document:
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" height="250">
|
||||
|
||||
Release version: [4.21c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release version: [4.30c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.22a
|
||||
GitHub version: 4.31a
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
@ -5,4 +5,5 @@ members = [
|
||||
"example",
|
||||
# Lain needs a nightly toolchain
|
||||
# "example_lain",
|
||||
]
|
||||
# "example_lain_post_process",
|
||||
]
|
||||
|
@ -5,7 +5,15 @@ Bindings to create custom mutators in Rust.
|
||||
These bindings are documented with rustdoc. To view the documentation run
|
||||
```cargo doc -p custom_mutator --open```.
|
||||
|
||||
A minimal example can be found in `example`. Build it using `cargo build --example example_mutator`.
|
||||
A minimal example can be found in `example`. Build it using `cargo build --example example_mutator`.
|
||||
|
||||
An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`.
|
||||
Since lain requires a nightly rust toolchain, you need to set one up before you can play with it.
|
||||
|
||||
An example for the use of the post_process function, using [lain](https://github.com/microsoft/lain) with [serde](https://github.com/serde-rs/serde) and [bincode](https://github.com/bincode-org/bincode) can be found in `example_lain_post_process`.
|
||||
In order for it to work you need to:
|
||||
|
||||
- disable input trimming with `AFL_DISABLE_TRIM=1`
|
||||
- provide an initial instance serialized with `bincode` or use the `AFL_NO_STARTUP_CALIBRATION=1` environment variable.
|
||||
|
||||
Note that `bincode` can also be used to serialize/deserialize the lain-generated structure and mutate it rather than generating a new one at each iteration, but it requires some structure serialized with `bincode` as input seed.
|
||||
|
@ -73,6 +73,8 @@ pub trait RawCustomMutator {
|
||||
None
|
||||
}
|
||||
|
||||
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]>;
|
||||
|
||||
/*fn post_process(&self, buffer: &[u8], unsigned char **out_buf)-> usize;
|
||||
int afl_custom_init_trim(&self, buffer: &[u8]);
|
||||
size_t afl_custom_trim(&self, unsigned char **out_buf);
|
||||
@ -353,6 +355,33 @@ pub mod wrappers {
|
||||
Err(err) => panic_handler("afl_custom_queue_get", &err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_post_process<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
) -> usize {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
|
||||
assert!(!buf.is_null(), "null buf passed to afl_custom_post_process");
|
||||
assert!(
|
||||
!out_buf.is_null(),
|
||||
"null out_buf passed to afl_custom_post_process"
|
||||
);
|
||||
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
|
||||
if let Some(buffer) = context.mutator.post_process(buff_slice) {
|
||||
*out_buf = buffer.as_ptr();
|
||||
return buffer.len();
|
||||
}
|
||||
0
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_post_process", &err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An exported macro to defined afl_custom_init meant for insternal usage
|
||||
@ -480,6 +509,16 @@ macro_rules! export_mutator {
|
||||
pub unsafe extern "C" fn afl_custom_deinit(data: *mut ::std::os::raw::c_void) {
|
||||
$crate::wrappers::afl_custom_deinit_::<$mutator_type>(data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn afl_custom_post_process(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
) -> usize {
|
||||
$crate::wrappers::afl_custom_post_process::<$mutator_type>(data, buf, buf_size, out_buf)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -512,6 +551,10 @@ mod sanity_test {
|
||||
) -> Option<&'b [u8]> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(ExampleMutator);
|
||||
@ -579,6 +622,13 @@ pub trait CustomMutator {
|
||||
fn introspection(&mut self) -> Result<Option<&str>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn post_process<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
) -> Result<Option<&'b [u8]>, Self::Error> {
|
||||
Ok(Some(buffer))
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> RawCustomMutator for M
|
||||
@ -682,6 +732,16 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn post_process<'b, 's: 'b>(&'s mut self, buffer: &'b mut [u8]) -> Option<&'b [u8]> {
|
||||
match self.post_process(buffer) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the default value to return from [`CustomMutator::describe`].
|
||||
|
@ -8,9 +8,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
lain="0.5"
|
||||
lain = { git = "https://github.com/AFLplusplus/lain.git" }
|
||||
|
||||
[[example]]
|
||||
name = "example_lain"
|
||||
path = "./src/lain_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
||||
crate-type = ["cdylib"]
|
||||
|
21
custom_mutators/rust/example_lain_post_process/Cargo.toml
Normal file
21
custom_mutators/rust/example_lain_post_process/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "example_lain_post_process"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Julius Hohnerlein <julihoh@users.noreply.github.com>",
|
||||
"jma <94166787+jma-qb@users.noreply.github.com>",
|
||||
]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
lain = { git = "https://github.com/AFLplusplus/lain.git" }
|
||||
bincode = "1.3.3"
|
||||
serde = { version = "1.0.214", features = ["derive"] }
|
||||
|
||||
[[example]]
|
||||
name = "example_lain_post_process"
|
||||
path = "./src/lain_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
@ -0,0 +1 @@
|
||||
nightly
|
@ -0,0 +1,70 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
use lain::{
|
||||
mutator::Mutator,
|
||||
prelude::*,
|
||||
rand::{rngs::StdRng, SeedableRng},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Mutatable, NewFuzzed, BinarySerialize)]
|
||||
struct MyStruct {
|
||||
tag: u8,
|
||||
#[lain(ignore)]
|
||||
length: u32,
|
||||
#[lain(min = 0, max = 10)]
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
struct LainMutator {
|
||||
mutator: Mutator<StdRng>,
|
||||
buffer: Vec<u8>,
|
||||
post_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CustomMutator for LainMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, ()> {
|
||||
Ok(Self {
|
||||
mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)),
|
||||
buffer: Vec::new(),
|
||||
post_buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_buffer: &'b mut [u8],
|
||||
_add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, ()> {
|
||||
// we just sample an instance of MyStruct, ignoring the current input
|
||||
let instance = MyStruct::new_fuzzed(&mut self.mutator, None);
|
||||
let serialized = bincode::serialize(&instance).unwrap();
|
||||
let size = serialized.len();
|
||||
if size > max_size {
|
||||
return Err(());
|
||||
}
|
||||
self.buffer.clear();
|
||||
self.buffer.reserve(size);
|
||||
self.buffer.extend_from_slice(&serialized);
|
||||
Ok(Some(self.buffer.as_slice()))
|
||||
}
|
||||
|
||||
fn post_process<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
) -> Result<Option<&'b [u8]>, Self::Error> {
|
||||
let mut instance = bincode::deserialize::<MyStruct>(&buffer).unwrap();
|
||||
instance.length = instance.data.len() as u32;
|
||||
let size = instance.serialized_size();
|
||||
self.post_buffer.clear();
|
||||
self.post_buffer.reserve(size);
|
||||
instance.binary_serialize::<_, BigEndian>(&mut self.post_buffer);
|
||||
Ok(Some(&self.post_buffer))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(LainMutator);
|
120
dictionaries/jsonschema.dict
Normal file
120
dictionaries/jsonschema.dict
Normal file
@ -0,0 +1,120 @@
|
||||
#
|
||||
# AFL dictionary for JSON Schema
|
||||
# https://json-schema.org/
|
||||
# -----------------------
|
||||
#
|
||||
|
||||
"\"$schema\""
|
||||
"\"$id\""
|
||||
"\"$ref\""
|
||||
"\"$defs\""
|
||||
"\"definitions\""
|
||||
"\"enum\""
|
||||
"\"const\""
|
||||
"\"type\""
|
||||
|
||||
# Annotations
|
||||
|
||||
"\"title\""
|
||||
"\"description\""
|
||||
"\"default\""
|
||||
"\"examples\""
|
||||
"\"$comment\""
|
||||
"\"readOnly\""
|
||||
"\"writeOnly\""
|
||||
"\"deprecated\""
|
||||
|
||||
# Types
|
||||
|
||||
"\"string\""
|
||||
"\"integer\""
|
||||
"\"number\""
|
||||
"\"object\""
|
||||
"\"array\""
|
||||
"\"null\""
|
||||
"\"boolean\""
|
||||
|
||||
# String
|
||||
|
||||
"\"minLength\""
|
||||
"\"maxLength\""
|
||||
"\"pattern\""
|
||||
"\"format\""
|
||||
"\"contentMediaType\""
|
||||
"\"contentEncoding\""
|
||||
"\"contentSchema\""
|
||||
|
||||
# Formats
|
||||
|
||||
"\"date-time\""
|
||||
"\"time\""
|
||||
"\"date\""
|
||||
"\"duration\""
|
||||
"\"email\""
|
||||
"\"idn-email\""
|
||||
"\"hostname\""
|
||||
"\"idn-hostname\""
|
||||
"\"ipv4\""
|
||||
"\"ipv6\""
|
||||
"\"uuid\""
|
||||
"\"uri\""
|
||||
"\"uri-reference\""
|
||||
"\"iri\""
|
||||
"\"iri-reference\""
|
||||
"\"uri-template\""
|
||||
"\"json-pointer\""
|
||||
"\"relative-json-pointer\""
|
||||
"\"regex\""
|
||||
|
||||
# Numeric
|
||||
|
||||
"\"multipleOf\""
|
||||
"\"minimum\""
|
||||
"\"exclusiveMinimum\""
|
||||
"\"maximum\""
|
||||
"\"exclusiveMaximum\""
|
||||
|
||||
# Object
|
||||
|
||||
"\"properties\""
|
||||
"\"patternProperties\""
|
||||
"\"additionalProperties\""
|
||||
"\"unevaluatedProperties\""
|
||||
"\"required\""
|
||||
"\"propertyNames\""
|
||||
"\"minProperties\""
|
||||
"\"maxProperties\""
|
||||
"\"dependencies\""
|
||||
|
||||
# Array
|
||||
|
||||
"\"items\""
|
||||
"\"prefixItems\""
|
||||
"\"additionalItems\""
|
||||
"\"unevaluatedItems\""
|
||||
"\"contains\""
|
||||
"\"minContains\""
|
||||
"\"maxContains\""
|
||||
"\"minItems\""
|
||||
"\"maxItems\""
|
||||
"\"uniqueItems\""
|
||||
|
||||
# Booleans
|
||||
|
||||
"true"
|
||||
"false"
|
||||
|
||||
# Composition
|
||||
|
||||
"\"allOf\""
|
||||
"\"anyOf\""
|
||||
"\"oneOf\""
|
||||
"\"not\""
|
||||
|
||||
# Conditions
|
||||
|
||||
"\"dependentRequired\""
|
||||
"\"dependentSchemas\""
|
||||
"\"if\""
|
||||
"\"then\""
|
||||
"\"else\""
|
@ -3,7 +3,8 @@
|
||||
This is the list of all noteworthy changes made in every public
|
||||
release of the tool. See README.md for the general instruction manual.
|
||||
|
||||
### Version ++4.22a (dev)
|
||||
### Version ++4.30c (release)
|
||||
! afl-gcc and afl-clang funcionality is now removed !
|
||||
- afl-fuzz:
|
||||
- fastresume feature added. if you abort fuzzing and resume fuzzing
|
||||
with `-i -` or `AFL_AUTORESUME=1` and the target binary has not changed
|
||||
@ -16,6 +17,8 @@
|
||||
- because of bad math and undefined behaviour fixes we have to change
|
||||
the CMPLOG map. **YOU NEED TO RECOMPILE CMPLOG TARGETS**
|
||||
- fixed custom_post_process for calibration
|
||||
- fixes for AFL_EXIT_ON_TIME and AFL_EXIT_WHEN_DONE, changed behaviour of
|
||||
AFL_EXIT_WHEN_DONE to finish when really done :-)
|
||||
- frida_mode:
|
||||
- AFL_FRIDA_PERSISTENT_ADDR can now be be any reachable address not just
|
||||
a function entry
|
||||
@ -26,6 +29,7 @@
|
||||
@CowBoy4mH3LL
|
||||
- unicorn_mode:
|
||||
- fix install and forkserver (thanks aarnav!)
|
||||
- pin unicorn version
|
||||
- nyx_mode:
|
||||
- bugfixes
|
||||
- custom mutators:
|
||||
@ -35,10 +39,14 @@
|
||||
- new runtime (!) variable: `AFL_OLD_FORKSERVER` to use the old vanilla
|
||||
AFL type forkserver. Useful for symcc/symqemu/nautilus/etc. with
|
||||
AFL_LLVM_INSTRUMENT=CLASSIC
|
||||
- new compile time variable: `AFL_OPT_LEVEL` to set a specific optimization
|
||||
level, default is `3`
|
||||
- correctly explain how to get the correct map size for large targets
|
||||
- small fix for weird LLVM defines in redhat
|
||||
- code formatting updated to llvm 18
|
||||
- improved custom_mutators/aflpp/standalone/aflpp-standalone
|
||||
- added custom_mutators/autotokens/standalone/autotokens-standalone
|
||||
|
||||
- AFL++ headers are now installed to $PREFIX/include/afl
|
||||
|
||||
### Version ++4.21c (release)
|
||||
* afl-fuzz
|
||||
|
@ -38,9 +38,8 @@ For PCGUARD instrumentation `abort()` is called if this is detected, for LTO
|
||||
there will either be no coverage for the instrumented dlopen()'ed libraries or
|
||||
you will see lots of crashes in the UI.
|
||||
|
||||
Note that this is not an issue if you use the inferiour `afl-gcc-fast`,
|
||||
`afl-gcc` or`AFL_LLVM_INSTRUMENT=CLASSIC/NGRAM/CTX afl-clang-fast`
|
||||
instrumentation.
|
||||
Note that this is not an issue if you use the inferiour `afl-gcc-fast`, or
|
||||
`AFL_LLVM_INSTRUMENT=CLASSIC/NGRAM/CTX afl-clang-fast` instrumentation.
|
||||
|
||||
### Fuzzing a binary-only target
|
||||
|
||||
|
@ -24,7 +24,6 @@ To select the different instrumentation modes, use one of the following options:
|
||||
- Use the `AFL_CC_COMPILER` environment variable with `MODE`. To select
|
||||
`MODE`, use one of the following values:
|
||||
|
||||
- `GCC` (afl-gcc/afl-g++)
|
||||
- `GCC_PLUGIN` (afl-g*-fast)
|
||||
- `LLVM` (afl-clang-fast*)
|
||||
- `LTO` (afl-clang-lto*).
|
||||
@ -45,14 +44,10 @@ fairly broad use of environment variables instead:
|
||||
make
|
||||
```
|
||||
|
||||
- Setting `AFL_AS`, `AFL_CC`, and `AFL_CXX` lets you use alternate downstream
|
||||
compilation tools, rather than the default 'as', 'clang', or 'gcc' binaries
|
||||
- Setting `AFL_CC`, and `AFL_CXX` lets you use alternate downstream
|
||||
compilation tools, rather than the default 'clang', or 'gcc' binaries
|
||||
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
|
||||
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
|
||||
@ -64,6 +59,9 @@ fairly broad use of environment variables instead:
|
||||
optimizations, set `AFL_DONT_OPTIMIZE`. However, if `-O...` and/or
|
||||
`-fno-unroll-loops` are set, these are not overridden.
|
||||
|
||||
- The optimization level can also be set with `AFL_OPT_LEVEL`, e.g.
|
||||
`AFL_OPT_LEVEL=z` for `-Oz`, default is `3`
|
||||
|
||||
- Setting `AFL_HARDEN` automatically adds code hardening options when invoking
|
||||
the downstream compiler. This currently includes `-D_FORTIFY_SOURCE=2` and
|
||||
`-fstack-protector-all`. The setting is useful for catching non-crashing
|
||||
@ -80,17 +78,13 @@ fairly broad use of environment variables instead:
|
||||
Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only
|
||||
the transitions between function entry points, but not individual branches.
|
||||
|
||||
Note that this is an outdated variable. A few instances (e.g., afl-gcc)
|
||||
still support these, but state-of-the-art (e.g., LLVM LTO and LLVM PCGUARD)
|
||||
do not need this.
|
||||
Note that this is an outdated variable. Only LLVM CLASSIC pass can use this.
|
||||
|
||||
- `AFL_NO_BUILTIN` causes the compiler to generate code suitable for use with
|
||||
libtokencap.so (but perhaps running a bit slower than without the flag).
|
||||
|
||||
- `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as.
|
||||
One possible use of this is utils/clang_asm_normalize/, which lets you
|
||||
instrument hand-written assembly when compiling clang code by plugging a
|
||||
normalizer into the chain. (There is no equivalent feature for GCC.)
|
||||
- `AFL_PATH` can be used to point a directory that contains LLVM/GCC plugins
|
||||
for AFL++, AFL++'s runtime objects and QEMU/Frida support files.
|
||||
|
||||
- Setting `AFL_QUIET` will prevent afl-as and afl-cc banners from being
|
||||
displayed during compilation, in case you find them distracting.
|
||||
@ -101,6 +95,7 @@ fairly broad use of environment variables instead:
|
||||
detection)
|
||||
- `AFL_USE_CFISAN=1` - activates the Control Flow Integrity sanitizer (e.g.
|
||||
type confusion vulnerabilities)
|
||||
- `AFL_CFISAN_VERBOSE=1` - outputs detailed information when control flow integrity violations occur, instead of simply terminating with "Illegal Instruction"
|
||||
- `AFL_USE_LSAN` - activates the leak sanitizer. To perform a leak check
|
||||
within your program at a certain point (such as at the end of an
|
||||
`__AFL_LOOP()`), you can run the macro `__AFL_LEAK_CHECK();` which will
|
||||
@ -111,6 +106,9 @@ fairly broad use of environment variables instead:
|
||||
- `AFL_USE_TSAN=1` - activates the thread sanitizer to find thread race
|
||||
conditions
|
||||
- `AFL_USE_UBSAN=1` - activates the undefined behavior sanitizer
|
||||
- `AFL_UBSAN_VERBOSE=1` - outputs detailed diagnostic information when undefined behavior is detected, instead of simply terminating with "Illegal Instruction"
|
||||
|
||||
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
|
||||
|
||||
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
|
||||
the tool defaults to /tmp.
|
||||
@ -323,6 +321,11 @@ mode.
|
||||
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
|
||||
for more information.
|
||||
|
||||
Setting `AFL_GCC_DISABLE_VERSION_CHECK=1` will disable the GCC plugin
|
||||
version check if the target GCC plugin differs from the system-installed
|
||||
version, resolving issues caused by version mismatches between GCC and
|
||||
the plugin.
|
||||
|
||||
Setting `AFL_GCC_OUT_OF_LINE=1` will instruct afl-gcc-fast to instrument the
|
||||
code with calls to an injected subroutine instead of the much more efficient
|
||||
inline instrumentation.
|
||||
@ -424,9 +427,8 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
types of automated jobs.
|
||||
|
||||
- `AFL_EXIT_WHEN_DONE` causes afl-fuzz to terminate when all existing paths
|
||||
have been fuzzed and there were no new finds for a while. This would be
|
||||
normally indicated by the cycle counter in the UI turning green. May be
|
||||
convenient for some types of automated jobs.
|
||||
have been fuzzed and there were no new finds for a while. This is basically
|
||||
when the fuzzing state says `state: finished`
|
||||
|
||||
- Setting `AFL_EXPAND_HAVOC_NOW` will start in the extended havoc mode that
|
||||
includes costly mutations. afl-fuzz automatically enables this mode when
|
||||
|
@ -6,20 +6,22 @@ QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
|
||||
|
||||
## 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) |
|
||||
| ------------------------------|:--------:|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
|
||||
| Threadsafe counters [A] | | x(3) | | | | | x | |
|
||||
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | |
|
||||
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
|
||||
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
|
||||
| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
|
||||
| Selective Instrumentation [F] | | x | x | x | x | | | |
|
||||
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | |
|
||||
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | |
|
||||
| Context Coverage [I] | | x(6) | | | | | | |
|
||||
| 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 | |
|
||||
Note that afl-gcc and afl-clang have been removed because their instrumentation is absolutely outdated.
|
||||
|
||||
| Feature/Instrumentation | llvm | gcc_plugin | FRIDA mode(9) | QEMU mode(10) | unicorn_mode(10) | nyx_mode(12) | coresight_mode(11) |
|
||||
| ------------------------------|:---------:|:----------:|:--------------:|:----------------:|:----------------:|:------------:|:------------------:|
|
||||
| Threadsafe counters [A] | x(3) | | | | | x | |
|
||||
| NeverZero [B] | x(1) | x | x | x | x | | |
|
||||
| Persistent Mode [C] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
|
||||
| LAF-Intel / CompCov [D] | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
|
||||
| CmpLog [E] | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
|
||||
| Selective Instrumentation [F] | x | x | x | x | | | |
|
||||
| Non-Colliding Coverage [G] | x(4) | | | (x)(5) | | | |
|
||||
| Ngram prev_loc Coverage [H] | x(6) | | | | | | |
|
||||
| Context Coverage [I] | x(6) | | | | | | |
|
||||
| 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
|
||||
|
||||
@ -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:
|
||||
|
||||
* 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
|
||||
* Persistent mode, deferred forkserver and in-memory fuzzing for QEMU mode
|
||||
* Unicorn mode which allows fuzzing of binaries from completely different
|
||||
|
@ -46,10 +46,9 @@ The following setup to use QEMU mode is recommended:
|
||||
`AFL_COMPCOV_LEVEL=2`), alternatively you can use FRIDA mode, just switch `-Q`
|
||||
with `-O` and remove the LAF instance
|
||||
|
||||
Then run as many instances as you have cores left with either -Q mode or - even
|
||||
better - use a binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
|
||||
The binary rewriters all have their own advantages and caveats.
|
||||
ZAFL is the best but cannot be used in a business/commercial context.
|
||||
Then run as many instances as you have cores left with either `-Q` mode or use
|
||||
a static binary rewriter like Dyninst, RetroWrite, ZAFL, etc.
|
||||
The binary rewriters all have their own advantages and caveats, but ZAFL is a good choice.
|
||||
|
||||
If a binary rewriter works for your target then you can use afl-fuzz normally
|
||||
and it will have twice the speed compared to QEMU mode (but slower than QEMU
|
||||
@ -200,6 +199,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
|
||||
(PIC/PIE), then the RetroWrite solution might be for you.
|
||||
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
|
||||
in performance to compiler-instrumented binaries and outperform the QEMU-based
|
||||
|
@ -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,
|
||||
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++)
|
||||
@ -84,7 +86,7 @@ anything below 9 is not recommended.
|
||||
| if not, or if you do not have a gcc with plugin support
|
||||
|
|
||||
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:
|
||||
@ -92,14 +94,12 @@ Clickable README links for the chosen compiler:
|
||||
* [LTO mode - afl-clang-lto](../instrumentation/README.lto.md)
|
||||
* [LLVM mode - afl-clang-fast](../instrumentation/README.llvm.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:
|
||||
|
||||
* 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-gcc-fast, afl-g++-fast (recommended!).
|
||||
afl-gcc-fast, afl-g++-fast.
|
||||
* Using the environment variable `AFL_CC_COMPILER` with `MODE`.
|
||||
* Passing --afl-`MODE` command line options to the compiler via
|
||||
`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*)
|
||||
* LLVM (afl-clang-fast*)
|
||||
* GCC_PLUGIN (afl-g*-fast) or GCC (afl-gcc/afl-g++)
|
||||
* CLANG(afl-clang/afl-clang++)
|
||||
* GCC_PLUGIN (afl-g*-fast)
|
||||
|
||||
Because no AFL++ specific command-line options are accepted (beside the
|
||||
--afl-MODE command), the compile-time tools make fairly broad use of environment
|
||||
@ -201,6 +200,9 @@ type. This is enough because e.g. a use-after-free bug will be picked up by ASAN
|
||||
(address sanitizer) anyway after syncing test cases from other fuzzing
|
||||
instances, so running more than one address sanitized target would be a waste.
|
||||
|
||||
*IF* you are running a saturated corpus, then you can run up to half of the
|
||||
instances with sanitizers.
|
||||
|
||||
The following sanitizers have built-in support in AFL++:
|
||||
|
||||
* ASAN = Address SANitizer, finds memory corruption vulnerabilities like
|
||||
|
775
include/afl-as.h
775
include/afl-as.h
@ -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 */
|
||||
|
@ -60,7 +60,7 @@ struct cmp_operands {
|
||||
u64 v1_128;
|
||||
u64 v1_256_0;
|
||||
u64 v1_256_1;
|
||||
u8 unused[8];
|
||||
u8 unused[8]; // 2 bits could be used for "is constant operand"
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
@ -70,7 +70,7 @@ struct cmpfn_operands {
|
||||
u8 v1[32];
|
||||
u8 v0_len;
|
||||
u8 v1_len;
|
||||
u8 unused[6];
|
||||
u8 unused[6]; // 2 bits could be used for "is constant operand"
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.22a"
|
||||
#define VERSION "++4.30c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
|
@ -20,20 +20,21 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_AUTORESUME", "AFL_AS_FORCE_INSTRUMENT", "AFL_BENCH_JUST_ONE",
|
||||
"AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
|
||||
"AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
|
||||
"AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
|
||||
"AFL_DUMP_CYCLOMATIC_COMPLEXITY", "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL",
|
||||
"AFL_CRASH_EXITCODE", "AFL_CRASHING_SEEDS_AS_NEW_CRASH",
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"AFL_CUSTOM_MUTATOR_LATE_SEND", "AFL_CUSTOM_INFO_PROGRAM",
|
||||
"AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT",
|
||||
"AFL_CUSTOM_INFO_OUT", "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG",
|
||||
"AFL_DEBUG_CHILD", "AFL_DEBUG_GDB", "AFL_DEBUG_UNICORN",
|
||||
"AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT", "AFL_DISABLE_TRIM",
|
||||
"AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION", "AFL_DONT_OPTIMIZE",
|
||||
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME", "AFL_DUMB_FORKSRV",
|
||||
"AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE",
|
||||
"AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL",
|
||||
"AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
||||
"AFL_CMPLOG_DEBUG", "AFL_CTX_K", "AFL_LLVM_DONTWRITEID", "AFL_PC_FILTER",
|
||||
"AFL_PC_FILTER_FILE", "AFL_CODE_END", "AFL_CODE_START",
|
||||
"AFL_COMPCOV_BINNAME", "AFL_DUMP_CYCLOMATIC_COMPLEXITY",
|
||||
"AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
|
||||
"AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_MUTATOR_LATE_SEND",
|
||||
"AFL_CUSTOM_INFO_PROGRAM", "AFL_CUSTOM_INFO_PROGRAM_ARGV",
|
||||
"AFL_CUSTOM_INFO_PROGRAM_INPUT", "AFL_CUSTOM_INFO_OUT", "AFL_CXX",
|
||||
"AFL_CYCLE_SCHEDULES", "AFL_DEBUG", "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB",
|
||||
"AFL_DEBUG_UNICORN", "AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT",
|
||||
"AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
|
||||
"AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||
"AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
|
||||
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
|
||||
"AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
||||
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
|
||||
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
|
||||
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
|
||||
@ -49,12 +50,12 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FRIDA_PERSISTENT_RET", "AFL_FRIDA_STALKER_ADJACENT_BLOCKS",
|
||||
"AFL_FRIDA_STALKER_IC_ENTRIES", "AFL_FRIDA_STALKER_NO_BACKPATCH",
|
||||
"AFL_FRIDA_STATS_FILE", "AFL_FRIDA_STATS_INTERVAL", "AFL_FRIDA_TRACEABLE",
|
||||
"AFL_FRIDA_VERBOSE", "AFL_OLD_FORKSERVER",
|
||||
"AFL_FRIDA_VERBOSE", "AFL_OLD_FORKSERVER", "AFL_OPT_LEVEL",
|
||||
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||
"AFL_FUZZER_STATS_UPDATE_INTERVAL", "AFL_GDB", "AFL_GCC_ALLOWLIST",
|
||||
"AFL_GCC_DENYLIST", "AFL_GCC_BLOCKLIST", "AFL_GCC_INSTRUMENT_FILE",
|
||||
"AFL_GCC_OUT_OF_LINE", "AFL_GCC_SKIP_NEVERZERO", "AFL_GCJ",
|
||||
"AFL_HANG_TMOUT", "AFL_FORKSRV_INIT_TMOUT", "AFL_HARDEN",
|
||||
"AFL_GCC_DENYLIST", "AFL_GCC_BLOCKLIST", "AFL_GCC_DISABLE_VERSION_CHECK",
|
||||
"AFL_GCC_INSTRUMENT_FILE", "AFL_GCC_OUT_OF_LINE", "AFL_GCC_SKIP_NEVERZERO",
|
||||
"AFL_GCJ", "AFL_HANG_TMOUT", "AFL_FORKSRV_INIT_TMOUT", "AFL_HARDEN",
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IGNORE_PROBLEMS",
|
||||
"AFL_IGNORE_PROBLEMS_COVERAGE", "AFL_IGNORE_SEED_PROBLEMS",
|
||||
"AFL_IGNORE_TIMEOUTS", "AFL_IGNORE_UNKNOWN_ENVS", "AFL_IMPORT_FIRST",
|
||||
@ -113,10 +114,10 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_STATSD_TAGS_FLAVOR", "AFL_SYNC_TIME", "AFL_TESTCACHE_SIZE",
|
||||
"AFL_TESTCACHE_ENTRIES", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE",
|
||||
"AFL_TRACE_PC", "AFL_USE_ASAN", "AFL_USE_MSAN", "AFL_USE_TRACE_PC",
|
||||
"AFL_USE_UBSAN", "AFL_USE_TSAN", "AFL_USE_CFISAN", "AFL_USE_LSAN",
|
||||
"AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN",
|
||||
"AFL_USE_QASAN", "AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE",
|
||||
"AFL_NO_FASTRESUME", NULL
|
||||
"AFL_USE_UBSAN", "AFL_UBSAN_VERBOSE", "AFL_USE_TSAN", "AFL_USE_CFISAN",
|
||||
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME", NULL
|
||||
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@ TL;DR:
|
||||
|
||||
The code in this directory allows to instrument programs for AFL++ using 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:
|
||||
|
||||
- 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
|
||||
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.
|
||||
|
||||
## 2) How to use
|
||||
@ -51,7 +47,10 @@ The idea and much of the implementation comes from Laszlo Szekeres.
|
||||
In order to leverage this mechanism, you need to have modern enough GCC (>=
|
||||
version 4.5.0) and the plugin development headers installed on your system. That
|
||||
should be all you need. On Debian machines, these headers can be acquired by
|
||||
installing the `gcc-VERSION-plugin-dev` packages.
|
||||
installing the `gcc-VERSION-plugin-dev` packages. If you're compiling a GCC
|
||||
plugin that differs from the system-installed version and encounter issues
|
||||
with version checks, you can use the `AFL_GCC_DISABLE_VERSION_CHECK` environment
|
||||
variable.
|
||||
|
||||
To build the instrumentation itself, type `make`. This will generate binaries
|
||||
called `afl-gcc-fast` and `afl-g++-fast` in the parent directory.
|
||||
@ -74,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.
|
||||
|
||||
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
|
||||
`AFL_INST_RATIO`, `AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`.
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
This file describes two different mechanisms to selectively instrument only
|
||||
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
|
||||
|
||||
|
@ -11,7 +11,7 @@ For the GCC-based instrumentation, see
|
||||
|
||||
The code in this directory allows you to instrument programs for AFL++ using
|
||||
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:
|
||||
|
||||
- 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
|
||||
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.
|
||||
|
||||
## 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
|
||||
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
|
||||
`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
|
||||
@ -255,10 +251,6 @@ low cost (one instruction per edge).
|
||||
(The alternative of saturated counters has been tested also and proved to be
|
||||
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,
|
||||
then set
|
||||
|
||||
|
@ -57,23 +57,23 @@ 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-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
|
||||
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).
|
||||
```
|
||||
|
||||
## Getting LLVM 12+
|
||||
## Getting LLVM 13+
|
||||
|
||||
### Installing llvm
|
||||
|
||||
The best way to install LLVM is to follow [https://apt.llvm.org/](https://apt.llvm.org/)
|
||||
|
||||
e.g. for LLVM 15:
|
||||
e.g. for LLVM 19:
|
||||
```
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15 all
|
||||
sudo ./llvm.sh 19 all
|
||||
```
|
||||
|
||||
LLVM 12 to 18 should be available in all current Linux repositories.
|
||||
LLVM 13 to 19 should be available in all current Linux repositories.
|
||||
|
||||
## How to build afl-clang-lto
|
||||
|
||||
@ -90,7 +90,7 @@ sudo make install
|
||||
|
||||
## 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 ->
|
||||
[README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov
|
||||
|
@ -124,7 +124,6 @@ will keep working normally when compiled with a tool other than 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!
|
||||
|
||||
## 4) Persistent mode
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include "llvm/IR/CFG.h"
|
||||
#endif
|
||||
#include "llvm/IR/Constant.h"
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/ValueSymbolTable.h"
|
||||
#endif
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#if LLVM_VERSION_MAJOR < 15
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
@ -306,7 +310,7 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
|
||||
Type *PtrTy = PointerType::getUnqual(Ty);
|
||||
std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
|
||||
M, CtorName, InitFunctionName, {PtrTy, PtrTy}, {SecStart, SecEnd});
|
||||
assert(CtorFunc->getName() == CtorName);
|
||||
// assert(CtorFunc->getName() == CtorName);
|
||||
|
||||
if (TargetTriple.supportsCOMDAT()) {
|
||||
|
||||
|
@ -367,6 +367,12 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: AFL_MAP_SIZE=%u\n", __afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
if (__afl_final_loc > MAP_SIZE) {
|
||||
|
||||
char *ptr;
|
||||
@ -413,7 +419,7 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); }
|
||||
|
||||
if (val > MAP_INITIAL_SIZE) {
|
||||
if (val > MAP_INITIAL_SIZE && val > __afl_final_loc) {
|
||||
|
||||
__afl_map_size = val;
|
||||
|
||||
@ -630,22 +636,22 @@ static void __afl_map_shm(void) {
|
||||
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_map_size);
|
||||
|
||||
if (__afl_area_ptr_dummy) {
|
||||
}
|
||||
|
||||
if (__afl_selective_coverage_start_off) {
|
||||
if (__afl_area_ptr_dummy) {
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
if (__afl_selective_coverage_start_off) {
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Error: __afl_selective_coverage failed!\n");
|
||||
__afl_selective_coverage = 0;
|
||||
// continue;
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Error: __afl_selective_coverage failed!\n");
|
||||
__afl_selective_coverage = 0;
|
||||
// continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -370,7 +370,8 @@ Set AFL_QUIET in the environment to silence it.\n\
|
||||
int plugin_init(struct plugin_name_args *info,
|
||||
struct plugin_gcc_version *version) {
|
||||
|
||||
if (!plugin_default_version_check(version, &gcc_version))
|
||||
if (!plugin_default_version_check(version, &gcc_version) &&
|
||||
!getenv("AFL_GCC_DISABLE_VERSION_CHECK"))
|
||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
|
||||
"is %s"),
|
||||
gcc_version.basever, version->basever);
|
||||
|
@ -338,7 +338,8 @@ Set AFL_QUIET in the environment to silence it.\n\
|
||||
int plugin_init(struct plugin_name_args *info,
|
||||
struct plugin_gcc_version *version) {
|
||||
|
||||
if (!plugin_default_version_check(version, &gcc_version))
|
||||
if (!plugin_default_version_check(version, &gcc_version) &&
|
||||
!getenv("AFL_GCC_DISABLE_VERSION_CHECK"))
|
||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
|
||||
"is %s"),
|
||||
gcc_version.basever, version->basever);
|
||||
|
@ -478,7 +478,8 @@ Specify -frandom-seed for reproducible instrumentation.\n\
|
||||
int plugin_init(struct plugin_name_args *info,
|
||||
struct plugin_gcc_version *version) {
|
||||
|
||||
if (!plugin_default_version_check(version, &gcc_version))
|
||||
if (!plugin_default_version_check(version, &gcc_version) &&
|
||||
!getenv("AFL_GCC_DISABLE_VERSION_CHECK"))
|
||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
|
||||
"is %s"),
|
||||
gcc_version.basever, version->basever);
|
||||
|
@ -168,6 +168,10 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
|
||||
void initInstrumentList() {
|
||||
|
||||
static int init = 0;
|
||||
if (init) return;
|
||||
init = 1;
|
||||
|
||||
char *allowlist = getenv("AFL_LLVM_ALLOWLIST");
|
||||
if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE");
|
||||
if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST");
|
||||
@ -250,7 +254,7 @@ void initInstrumentList() {
|
||||
|
||||
if (debug)
|
||||
DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
|
||||
allowListFiles.size() / 4, allowListFunctions.size() / 4);
|
||||
allowListFiles.size(), allowListFunctions.size());
|
||||
|
||||
}
|
||||
|
||||
@ -325,7 +329,7 @@ void initInstrumentList() {
|
||||
|
||||
if (debug)
|
||||
DEBUGF("loaded denylist with %zu file and %zu function entries\n",
|
||||
denyListFiles.size() / 4, denyListFunctions.size() / 4);
|
||||
denyListFiles.size(), denyListFunctions.size());
|
||||
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,13 @@
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<optional>)
|
||||
#include <optional>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
@ -5,9 +5,6 @@
|
||||
Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
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 2019-2024 AFLplusplus Project. All rights reserved.
|
||||
|
||||
@ -17,10 +14,6 @@
|
||||
|
||||
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
|
||||
|
@ -6,9 +6,6 @@
|
||||
Adrian Herrera <adrian.herrera@anu.edu.au>,
|
||||
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.
|
||||
|
||||
Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
@ -20,10 +17,6 @@
|
||||
|
||||
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
|
||||
|
@ -1 +1 @@
|
||||
d40bcd8965
|
||||
4d837f06d5
|
||||
|
@ -1,3 +1,6 @@
|
||||
# Short talk
|
||||
[Open Source Security Foundation'24]( https://www.youtube.com/watch?v=qx1PCjQ1bCA&t=307s )
|
||||
|
||||
# Native hooking support into QEMUAFL
|
||||
* The essential idea is to have inbuilt hooking support into QEMU, instead of relying on the more expensive options UNICORN and its children.
|
||||
* This solution comprises a bridge (QEMU plugin) that connects your hooks (in a shared library (.so)) with the QEMU usermode ecosystem.
|
||||
|
Submodule qemu_mode/qemuafl updated: d40bcd8965...4d837f06d5
@ -513,7 +513,8 @@ static void dump_hex(u32 len, u8 *b_data) {
|
||||
static void analyze() {
|
||||
|
||||
u32 i;
|
||||
u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
|
||||
u32 boring_len = 0;
|
||||
u64 prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
|
||||
|
||||
u8 *b_data = ck_alloc(in_len + 1);
|
||||
u8 seq_byte = 0;
|
||||
|
671
src/afl-as.c
671
src/afl-as.c
@ -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));
|
||||
|
||||
}
|
||||
|
96
src/afl-cc.c
96
src/afl-cc.c
@ -98,7 +98,8 @@ typedef enum {
|
||||
|
||||
} compiler_mode_id;
|
||||
|
||||
static u8 cwd[4096];
|
||||
static u8 cwd[4096];
|
||||
static char opt_level = '3';
|
||||
|
||||
char instrument_mode_string[18][18] = {
|
||||
|
||||
@ -601,7 +602,6 @@ void compiler_mode_by_callname(aflcc_state_t *aflcc) {
|
||||
if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
|
||||
|
||||
/* 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),
|
||||
or too old, it falls back to LLVM-NATIVE mode and let
|
||||
the actual compiler complain if doesn't work.
|
||||
@ -881,9 +881,17 @@ static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
|
||||
*/
|
||||
static void instrument_mode_new_environ(aflcc_state_t *aflcc) {
|
||||
|
||||
u8 *ptr2;
|
||||
|
||||
if ((ptr2 = getenv("AFL_OPT_LEVEL"))) {
|
||||
|
||||
opt_level = ptr2[0]; // ignore invalid data
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_LLVM_INSTRUMENT")) { return; }
|
||||
|
||||
u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
|
||||
ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
|
||||
|
||||
while (ptr2) {
|
||||
|
||||
@ -1211,11 +1219,8 @@ void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) {
|
||||
switch (aflcc->compiler_mode) {
|
||||
|
||||
case GCC:
|
||||
if (!aflcc->have_gcc) FATAL("afl-gcc is not available on your platform!");
|
||||
break;
|
||||
case CLANG:
|
||||
if (!aflcc->have_clang)
|
||||
FATAL("afl-clang is not available on your platform!");
|
||||
break;
|
||||
case LLVM:
|
||||
if (!aflcc->have_llvm)
|
||||
@ -1555,7 +1560,6 @@ void add_defs_selective_instr(aflcc_state_t *aflcc) {
|
||||
/*
|
||||
Macro defs for persistent mode. As documented in
|
||||
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) {
|
||||
|
||||
@ -1936,11 +1940,15 @@ void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
|
||||
|
||||
if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
|
||||
|
||||
if (!aflcc->have_ubsan) {
|
||||
if (!aflcc->have_ubsan) { insert_param(aflcc, "-fsanitize=undefined"); }
|
||||
|
||||
insert_param(aflcc, "-fsanitize=undefined");
|
||||
insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
|
||||
insert_param(aflcc, "-fno-sanitize-recover=all");
|
||||
if (getenv("AFL_UBSAN_VERBOSE")) {
|
||||
|
||||
insert_param(aflcc, "-fno-sanitize-recover=undefined");
|
||||
|
||||
} else {
|
||||
|
||||
insert_param(aflcc, "-fsanitize-trap=undefined");
|
||||
|
||||
}
|
||||
|
||||
@ -2001,6 +2009,12 @@ void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
|
||||
|
||||
if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
|
||||
|
||||
if (getenv("AFL_CFISAN_VERBOSE")) {
|
||||
|
||||
insert_param(aflcc, "-fno-sanitize-trap=cfi");
|
||||
|
||||
}
|
||||
|
||||
if (!aflcc->have_hidden) {
|
||||
|
||||
insert_param(aflcc, "-fvisibility=hidden");
|
||||
@ -2561,6 +2575,33 @@ void add_gcc_plugin(aflcc_state_t *aflcc) {
|
||||
|
||||
}
|
||||
|
||||
char *get_opt_level() {
|
||||
|
||||
static char levels[8][8] = {"-O0", "-O1", "-O2", "-O3",
|
||||
"-Oz", "-Os", "-Ofast", "-Og"};
|
||||
switch (opt_level) {
|
||||
|
||||
case '0':
|
||||
return levels[0];
|
||||
case '1':
|
||||
return levels[1];
|
||||
case '2':
|
||||
return levels[2];
|
||||
case 'z':
|
||||
return levels[4];
|
||||
case 's':
|
||||
return levels[5];
|
||||
case 'f':
|
||||
return levels[6];
|
||||
case 'g':
|
||||
return levels[7];
|
||||
default:
|
||||
return levels[3];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Add some miscellaneous params required by our instrumentation. */
|
||||
void add_misc_params(aflcc_state_t *aflcc) {
|
||||
|
||||
@ -2592,7 +2633,7 @@ void add_misc_params(aflcc_state_t *aflcc) {
|
||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
insert_param(aflcc, "-g");
|
||||
if (!aflcc->have_o) insert_param(aflcc, "-O3");
|
||||
if (!aflcc->have_o) insert_param(aflcc, get_opt_level());
|
||||
if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
|
||||
// if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
|
||||
// insert_param(aflcc, aflcc->march_opt);
|
||||
@ -2810,10 +2851,7 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
|
||||
" yes\n"
|
||||
" [GCC_PLUGIN] gcc plugin: %s%s\n"
|
||||
" CLASSIC DEFAULT no yes no no no "
|
||||
"yes\n"
|
||||
" [GCC/CLANG] simple gcc/clang: %s%s\n"
|
||||
" CLASSIC DEFAULT no no no no no "
|
||||
"no\n\n",
|
||||
"yes\n\n",
|
||||
aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
|
||||
aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
|
||||
aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
|
||||
@ -2821,15 +2859,7 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
|
||||
aflcc->have_lto ? "AVAILABLE" : "unavailable!",
|
||||
aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
|
||||
aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
|
||||
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]"
|
||||
: "");
|
||||
aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "");
|
||||
|
||||
SAYF(
|
||||
"Modes:\n"
|
||||
@ -2922,6 +2952,8 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
|
||||
SAYF(
|
||||
"\nGCC Plugin-specific environment variables:\n"
|
||||
" AFL_GCC_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
|
||||
" AFL_GCC_DISABLE_VERSION_CHECK: disable GCC plugin version "
|
||||
"control\n"
|
||||
" AFL_GCC_OUT_OF_LINE: disable inlined instrumentation\n"
|
||||
" AFL_GCC_SKIP_NEVERZERO: do not skip zero on trace counters\n"
|
||||
" AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
|
||||
@ -3517,15 +3549,27 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
maybe_usage(aflcc, argc, argv);
|
||||
|
||||
if (aflcc->instrument_mode == INSTRUMENT_GCC ||
|
||||
aflcc->instrument_mode == INSTRUMENT_CLANG) {
|
||||
|
||||
FATAL(
|
||||
"afl-gcc/afl-clang are obsolete and has been removed. Use "
|
||||
"afl-clang-fast/afl-gcc-fast for instrumentation instead.");
|
||||
|
||||
}
|
||||
|
||||
mode_notification(aflcc);
|
||||
|
||||
if (aflcc->debug) debugf_args(argc, argv);
|
||||
|
||||
edit_params(aflcc, argc, argv, envp);
|
||||
|
||||
if (aflcc->debug)
|
||||
if (aflcc->debug) {
|
||||
|
||||
debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
|
||||
|
||||
}
|
||||
|
||||
if (aflcc->passthrough) {
|
||||
|
||||
argv[0] = aflcc->cc_params[0];
|
||||
|
@ -495,9 +495,9 @@ static void report_error_and_exit(int error) {
|
||||
FATAL(
|
||||
"AFL_MAP_SIZE is not set and fuzzing target reports that the "
|
||||
"required size is very large. Solution: Run the fuzzing target "
|
||||
"stand-alone with the environment variable AFL_DEBUG=1 set and set "
|
||||
"the value for __afl_final_loc in the AFL_MAP_SIZE environment "
|
||||
"variable for afl-fuzz.");
|
||||
"stand-alone with the environment variable AFL_DUMP_MAP_SIZE=1 set "
|
||||
"the displayed value in the AFL_MAP_SIZE environment variable for "
|
||||
"afl-fuzz.");
|
||||
break;
|
||||
case FS_ERROR_MAP_ADDR:
|
||||
FATAL(
|
||||
@ -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
|
||||
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,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output) {
|
||||
|
@ -1714,8 +1714,12 @@ static u8 delete_files(u8 *path, u8 *prefix) {
|
||||
|
||||
while ((d_ent = readdir(d))) {
|
||||
|
||||
if (d_ent->d_name[0] != '.' &&
|
||||
(!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix)))) {
|
||||
if ((d_ent->d_name[0] != '.' &&
|
||||
(!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix))))
|
||||
/* heiko: don't forget the SHA1 files */
|
||||
|| strspn(d_ent->d_name, "0123456789abcdef") ==
|
||||
2 * 20 /* TODO use 2 * HASH_LENGTH */
|
||||
) {
|
||||
|
||||
u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
|
||||
if (unlink(fname)) { PFATAL("Unable to delete '%s'", fname); }
|
||||
@ -3092,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)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"This program appears to be instrumented with afl-gcc, but is being "
|
||||
"run in\n"
|
||||
" QEMU mode (-Q). This is probably not what you "
|
||||
"This program appears to be instrumented with AFL++ compilers, but is "
|
||||
"being run\n"
|
||||
" in QEMU mode (-Q). This is probably not what you "
|
||||
"want -\n"
|
||||
" this setup will be slow and offer no practical benefits.\n");
|
||||
|
||||
|
@ -56,6 +56,8 @@ char *get_fuzzing_state(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
|
||||
|
||||
return fuzzing_state[3];
|
||||
|
||||
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
|
||||
@ -822,15 +824,6 @@ void show_stats_normal(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
|
||||
!afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) {
|
||||
|
||||
afl->stop_soon = 2;
|
||||
|
||||
}
|
||||
|
||||
/* AFL_EXIT_ON_TIME. */
|
||||
|
||||
/* If no coverage was found yet, check whether run time is greater than
|
||||
@ -998,14 +991,14 @@ void show_stats_normal(afl_state_t *afl) {
|
||||
} else
|
||||
|
||||
/* Subsequent cycles, but we're still making finds. */
|
||||
if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
|
||||
if (afl->cycles_wo_finds < 2 || min_wo_finds <= 30) {
|
||||
|
||||
strcpy(tmp, cYEL);
|
||||
|
||||
} else
|
||||
|
||||
/* No finds for a long time and no test cases to try. */
|
||||
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
|
||||
if (afl->cycles_wo_finds > 1 && !afl->pending_not_fuzzed &&
|
||||
min_wo_finds > 120) {
|
||||
|
||||
strcpy(tmp, cLGN);
|
||||
@ -1656,15 +1649,6 @@ void show_stats_pizza(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
|
||||
!afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) {
|
||||
|
||||
afl->stop_soon = 2;
|
||||
|
||||
}
|
||||
|
||||
/* AFL_EXIT_ON_TIME. */
|
||||
|
||||
/* If no coverage was found yet, check whether run time is greater than
|
||||
@ -1813,14 +1797,14 @@ void show_stats_pizza(afl_state_t *afl) {
|
||||
} else
|
||||
|
||||
/* Subsequent cycles, but we're still making finds. */
|
||||
if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
|
||||
if (afl->cycles_wo_finds < 2 || min_wo_finds <= 30) {
|
||||
|
||||
strcpy(tmp, cYEL);
|
||||
|
||||
} else
|
||||
|
||||
/* No finds for a long time and no test cases to try. */
|
||||
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
|
||||
if (afl->cycles_wo_finds > 1 && !afl->pending_not_fuzzed &&
|
||||
min_wo_finds > 120) {
|
||||
|
||||
strcpy(tmp, cLGN);
|
||||
|
@ -671,10 +671,28 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 'g':
|
||||
afl->min_length = atoi(optarg);
|
||||
|
||||
if (afl->min_length < 1) { afl->min_length = 1; }
|
||||
if (afl->min_length >= MAX_FILE) {
|
||||
|
||||
FATAL("Option -g must be below %lu", (long unsigned int)MAX_FILE);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
afl->max_length = atoi(optarg);
|
||||
if (afl->max_length < 4) { afl->max_length = 4; }
|
||||
if (afl->max_length > MAX_FILE) {
|
||||
|
||||
FATAL(
|
||||
"Option -G max value is %lu, change by editing config.h and "
|
||||
"recompiling afl-fuzz.",
|
||||
(long unsigned int)MAX_FILE);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
@ -2937,9 +2955,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
3600 */
|
||||
)) {
|
||||
|
||||
if (afl->use_splicing) {
|
||||
++afl->cycles_wo_finds;
|
||||
|
||||
++afl->cycles_wo_finds;
|
||||
if (afl->use_splicing) {
|
||||
|
||||
if (unlikely(afl->shm.cmplog_mode &&
|
||||
afl->cmplog_max_filesize < MAX_FILE)) {
|
||||
|
@ -4,60 +4,58 @@
|
||||
|
||||
OS=$(uname -s)
|
||||
|
||||
AFL_GCC=afl-gcc
|
||||
$ECHO "$BLUE[*] Testing: ${AFL_GCC}, 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_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && {
|
||||
../${AFL_GCC} -v 2>&1 | grep -qi "gcc version" && {
|
||||
../${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
|
||||
AFL_COMPILER=afl-clang-fast
|
||||
$ECHO "$BLUE[*] Testing: ${AFL_COMPILER}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
|
||||
test -e ../${AFL_COMPILER} -a -e ../afl-showmap -a -e ../afl-fuzz && {
|
||||
../${AFL_COMPILER} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
|
||||
AFL_HARDEN=1 ../${AFL_COMPILER} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
|
||||
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
|
||||
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_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
|
||||
} || {
|
||||
$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
|
||||
}
|
||||
rm -f test-instr.plain.0 test-instr.plain.1
|
||||
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}'`
|
||||
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
|
||||
}
|
||||
test "$TUPLES" -lt 3 && SKIP=1
|
||||
true # this is needed because of the test above
|
||||
} || {
|
||||
$ECHO "$RED[!] ${AFL_GCC} failed"
|
||||
$ECHO "$RED[!] ${AFL_COMPILER} failed"
|
||||
echo CUT------------------------------------------------------------------CUT
|
||||
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
|
||||
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_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'
|
||||
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
|
||||
CODE=1
|
||||
}
|
||||
rm -f test-compcov.harden
|
||||
} || {
|
||||
$ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed"
|
||||
$ECHO "$RED[!] ${AFL_COMPILER} hardened mode compilation failed"
|
||||
CODE=1
|
||||
}
|
||||
# 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
|
||||
echo 0 > in/in
|
||||
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
|
||||
} >>errors 2>&1
|
||||
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
|
||||
cat errors
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -124,159 +122,9 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
|
||||
unset AFL_QUIET
|
||||
}
|
||||
rm -f test-instr.plain
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] afl-gcc executes clang, cannot test!"
|
||||
INCOMPLETE=1
|
||||
}
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] afl is not compiled, cannot test"
|
||||
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
|
||||
|
@ -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 && {
|
||||
../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 -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
|
||||
}
|
||||
# Compile the vulnerable program for multiple mutators
|
||||
test -e ../afl-clang-fast && {
|
||||
../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 -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
|
||||
}
|
||||
# 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
|
||||
|
@ -19,7 +19,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
|
||||
} || {
|
||||
$ECHO "$GREEN[+] gcc_plugin instrumentation present and working correctly"
|
||||
TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain.gccpi 2>&1 | grep Captur | awk '{print$3}'`
|
||||
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 9 && {
|
||||
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 10 && {
|
||||
$ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine"
|
||||
} || {
|
||||
$ECHO "$RED[!] gcc_plugin instrumentation produces a weird numbers: $TUPLES"
|
||||
@ -81,7 +81,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
|
||||
|
||||
# now for the special gcc_plugin things
|
||||
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 && {
|
||||
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"
|
||||
|
@ -26,7 +26,7 @@ unset AFL_USE_ASAN
|
||||
unset AFL_USE_MSAN
|
||||
unset AFL_CC
|
||||
unset AFL_PRELOAD
|
||||
unset AFL_GCC_INSTRUMENT_FILE
|
||||
unset AFL_COMPILER_INSTRUMENT_FILE
|
||||
unset AFL_LLVM_INSTRUMENT_FILE
|
||||
unset AFL_LLVM_INSTRIM
|
||||
unset AFL_LLVM_LAF_SPLIT_SWITCHES
|
||||
@ -37,15 +37,6 @@ unset AFL_LLVM_LAF_SPLIT_COMPARES
|
||||
test -e /usr/local/bin/opt && {
|
||||
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 \\101 2>&1 | grep -qE '^A' || {
|
||||
@ -76,30 +67,6 @@ echo
|
||||
|
||||
$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"
|
||||
LLVM=x
|
||||
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 "$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 "$GREY[*] done."
|
||||
|
@ -111,14 +111,7 @@ test -n "$TRAVIS_OS_NAME" && {
|
||||
test -e /usr/local/bin/opt && {
|
||||
test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
|
||||
}
|
||||
# on MacOS X we prefer afl-clang over afl-gcc, because
|
||||
# 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
|
||||
AFL_COMPILER=afl-clang-fast
|
||||
|
||||
SYS=`uname -m`
|
||||
|
||||
|
@ -1 +1 @@
|
||||
1c58dc97
|
||||
2abdcd3c
|
||||
|
Submodule unicorn_mode/unicornafl updated: 1c58dc9774...2abdcd3c79
Reference in New Issue
Block a user