From 7b24f4a32931290b65ecb7b6826fd49e4a2d66d6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 21 Nov 2024 14:31:36 +0100 Subject: [PATCH 1/3] remove afl-gcc/afl-clang --- GNUmakefile | 38 +- docs/env_variables.md | 18 +- docs/features.md | 32 +- docs/fuzzing_binary-only_targets.md | 1 + docs/fuzzing_in_depth.md | 13 +- include/afl-as.h | 775 ------------------ instrumentation/README.gcc_plugin.md | 8 +- instrumentation/README.instrument_list.md | 2 +- instrumentation/README.llvm.md | 12 +- instrumentation/README.lto.md | 6 +- instrumentation/README.persistent_mode.md | 1 - .../afl-llvm-lto-instrumentlist.so.cc | 7 - instrumentation/afl-llvm-pass.so.cc | 7 - src/afl-as.c | 671 --------------- src/afl-cc.c | 33 +- src/afl-forkserver.c | 2 +- src/afl-fuzz-init.c | 6 +- test/test-basic.sh | 192 +---- test/test-custom-mutators.sh | 12 +- test/test-gcc-plugin.sh | 2 +- test/test-performance.sh | 37 +- test/test-pre.sh | 9 +- 22 files changed, 95 insertions(+), 1789 deletions(-) delete mode 100644 include/afl-as.h delete mode 100644 src/afl-as.c diff --git a/GNUmakefile b/GNUmakefile index ea59f382..980f2b6b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -30,12 +30,10 @@ 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 -HEADERS = include/afl-as.h include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h -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) @@ -327,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" @@ -339,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 @@ -465,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 @@ -576,7 +573,7 @@ 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 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 @@ -585,18 +582,18 @@ test_build: afl-cc afl-gcc afl-as afl-showmap @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi @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 @@ -606,7 +603,8 @@ all_done: test_build @test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!" @test -e 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 @@ -614,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-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 @@ -831,8 +829,6 @@ endif 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) @@ -840,9 +836,9 @@ 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 + -cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt injections.dic -rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries -sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f" -cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES) diff --git a/docs/env_variables.md b/docs/env_variables.md index d1edb6fd..8b4f441e 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -45,14 +45,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 @@ -83,17 +79,13 @@ fairly broad use of environment variables instead: Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only 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. diff --git a/docs/features.md b/docs/features.md index 212302f8..b75c103c 100644 --- a/docs/features.md +++ b/docs/features.md @@ -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 diff --git a/docs/fuzzing_binary-only_targets.md b/docs/fuzzing_binary-only_targets.md index a151bce4..4dbfb1eb 100644 --- a/docs/fuzzing_binary-only_targets.md +++ b/docs/fuzzing_binary-only_targets.md @@ -200,6 +200,7 @@ have an x86_64 or arm64 binary that does not contain C++ exceptions and - if x86_64 - still has it's symbols and compiled with position independent code (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 diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md index 14682489..39be12a7 100644 --- a/docs/fuzzing_in_depth.md +++ b/docs/fuzzing_in_depth.md @@ -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 diff --git a/include/afl-as.h b/include/afl-as.h deleted file mode 100644 index c005d43d..00000000 --- a/include/afl-as.h +++ /dev/null @@ -1,775 +0,0 @@ -/* - american fuzzy lop++ - injectable parts - --------------------------------------- - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse , - Heiko Eissfeldt , - Andrea Fioraldi , - Dominik Maier - - 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 */ - diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md index 34004dc7..9f6aabf6 100644 --- a/instrumentation/README.gcc_plugin.md +++ b/instrumentation/README.gcc_plugin.md @@ -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 @@ -77,7 +73,7 @@ standard operating mode of AFL++, e.g.: Note: We also used `CXX` to set the C++ compiler to `afl-g++-fast` for C++ code. -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`. diff --git a/instrumentation/README.instrument_list.md b/instrumentation/README.instrument_list.md index 3ed64807..d5569213 100644 --- a/instrumentation/README.instrument_list.md +++ b/instrumentation/README.instrument_list.md @@ -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 diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 34b80c85..46f95514 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -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 diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md index bd479c26..9e91f8df 100644 --- a/instrumentation/README.lto.md +++ b/instrumentation/README.lto.md @@ -57,8 +57,8 @@ libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtif afl-clang-lto++2.63d by Marc "vanHauser" Heuse in mode LTO afl-llvm-lto++2.63d by Marc "vanHauser" Heuse AUTODICTIONARY: 11 strings found -[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). -``` +[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-clang-fast CLASSIC) (non-hardened mode). +s``` ## Getting LLVM 12+ @@ -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 diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md index 8e4f6ae4..41782b5b 100644 --- a/instrumentation/README.persistent_mode.md +++ b/instrumentation/README.persistent_mode.md @@ -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 diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index e0899cd3..17abe2a8 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -5,9 +5,6 @@ Written by Laszlo Szekeres 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 diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 75b8532b..8620fb3f 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -6,9 +6,6 @@ Adrian Herrera , 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 diff --git a/src/afl-as.c b/src/afl-as.c deleted file mode 100644 index d4ddb94d..00000000 --- a/src/afl-as.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - american fuzzy lop++ - wrapper for GNU as - ----------------------------------------- - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse , - Heiko Eissfeldt and - Andrea Fioraldi - - 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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: */ - - if ((colon_pos = strstr(line, ":"))) { - - if (line[0] == 'L' && isdigit(*(colon_pos - 1))) { - -#else - - /* Everybody else: .L: */ - - if (strstr(line, ":")) { - - if (line[0] == '.') { - -#endif /* __APPLE__ */ - - /* .L0: or LBB0_0: style jump destination */ - -#ifdef __APPLE__ - - /* Apple: L / LBB */ - - if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) && - R(100) < (long)inst_ratio) { - -#else - - /* Apple: .L / .LBB */ - - 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)); - -} - diff --git a/src/afl-cc.c b/src/afl-cc.c index f47f3d50..052f195d 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -602,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. @@ -1220,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) @@ -1564,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) { @@ -2845,10 +2840,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!", @@ -2856,15 +2848,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" @@ -3554,10 +3538,12 @@ int main(int argc, char **argv, char **envp) { maybe_usage(aflcc, argc, argv); - if ((aflcc->compiler_mode == CLANG || aflcc->compiler_mode == GCC) && - aflcc->need_aflpplib) { + if (aflcc->instrument_mode == INSTRUMENT_GCC || aflcc->instrument_mode == + INSTRUMENT_CLANG) { - FATAL("afl-gcc/afl-clang cannot be used together with -fsanitize=fuzzer"); + FATAL( + "afl-gcc/afl-clang are obsolete and has been removed. Use " + "afl-clang-fast/afl-gcc-fast for instrumentation instead."); } @@ -3567,9 +3553,12 @@ int main(int argc, char **argv, char **envp) { edit_params(aflcc, argc, argv, envp); - 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]; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 9f619c14..bee7f1bd 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -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) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index adf38adc..e90495f3 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -3096,9 +3096,9 @@ void check_binary(afl_state_t *afl, u8 *fname) { afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { 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"); diff --git a/test/test-basic.sh b/test/test-basic.sh index 7005d3ce..3f829497 100755 --- a/test/test-basic.sh +++ b/test/test-basic.sh @@ -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 diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index 3f0a96ba..871e0e4b 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.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 diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index 6f32c8e0..04da5d9c 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -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" diff --git a/test/test-performance.sh b/test/test-performance.sh index 50957141..8af59997 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -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." diff --git a/test/test-pre.sh b/test/test-pre.sh index ce996415..cc634442 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -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` From 48002fe146daf8285a495e461761d5ec775d21ae Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 21 Nov 2024 16:15:04 +0100 Subject: [PATCH 2/3] remove symlinks --- GNUmakefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 980f2b6b..6903cb07 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -821,10 +821,10 @@ install: all $(MANPAGES) ifneq "$(SYS)" "Darwin" -$(MAKE) -f GNUmakefile.gcc_plugin install endif - ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc - 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++ + #ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc + #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) From 8e88ef02add16a3da9a9e261f4b7eba128ccacc3 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 2 Dec 2024 14:54:16 +0100 Subject: [PATCH 3/3] keep symlinks --- GNUmakefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 6903cb07..980f2b6b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -821,10 +821,10 @@ install: all $(MANPAGES) ifneq "$(SYS)" "Darwin" -$(MAKE) -f GNUmakefile.gcc_plugin install endif - #ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc - #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++ + ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc + 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)