mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
218 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc7c4c763a | |||
d8e1c65418 | |||
a68d6ff1a0 | |||
afeb870045 | |||
ed3b03c95f | |||
6e5ca0c78c | |||
f37c4c8662 | |||
da33510855 | |||
db96b04aba | |||
0966957631 | |||
dcbfc88e7d | |||
d518426335 | |||
03bae6c4fe | |||
317a9df668 | |||
819ad95f03 | |||
3e1d794107 | |||
15fc47a62c | |||
7b1238b0f4 | |||
32d5ccb92d | |||
aaa1d113e7 | |||
cac713ec30 | |||
1e3890ea7f | |||
edd352612d | |||
2106738d6b | |||
0616f368c8 | |||
c2c27349c3 | |||
b28b63f873 | |||
9926f07082 | |||
90f83c13d0 | |||
224e884ba1 | |||
93362c6e67 | |||
ec4ed66b1e | |||
64b15a00f2 | |||
936b6dcb5d | |||
2366c00235 | |||
51ab51ca27 | |||
68aacc4269 | |||
7b29f2cd24 | |||
420e36dcd3 | |||
a0242db421 | |||
450e00446d | |||
4231d33bc0 | |||
a360344247 | |||
9a0931858a | |||
fc1e352965 | |||
091d66fa92 | |||
3ad8e9856c | |||
f1a616406e | |||
61b6f4ed9e | |||
ed97dbacef | |||
af8c68a774 | |||
25eba95bba | |||
bf2727b763 | |||
6ec70fc084 | |||
31e2c6c2b4 | |||
c28779adc5 | |||
e71d422b3c | |||
88603a2c2e | |||
a4b9272416 | |||
f6471dd256 | |||
26cbc1e993 | |||
f0ccca123a | |||
c7c6ad1a94 | |||
14e25340fb | |||
9b2c4a2a5a | |||
62bacf4fc8 | |||
7c84331dc5 | |||
ee2cab73ac | |||
4deb45f3b3 | |||
8de7f6131d | |||
2f6b54e441 | |||
234d55ccd5 | |||
993d0c267d | |||
281f6c1ea1 | |||
9585f5cdfe | |||
abc26a932a | |||
28fd971608 | |||
f9b72b6f2f | |||
b644e48f36 | |||
2b500ce97e | |||
9324f3f628 | |||
63a7a816e7 | |||
06e1c64745 | |||
7870ece6dc | |||
e596c9856b | |||
ed73c632a5 | |||
ad8f7d6eb3 | |||
074b5ba54d | |||
b08e6bf8c6 | |||
c7ced56066 | |||
287128a196 | |||
c9dfc279c7 | |||
c323e0dc63 | |||
b10a091408 | |||
eeed38c5f8 | |||
501226c992 | |||
8e1df8e53d | |||
8985524d3a | |||
b81e0fece6 | |||
22837b5ad2 | |||
dd736126dc | |||
d5e3223f03 | |||
029e039cbc | |||
1416fea160 | |||
d4085314c1 | |||
9a6c0ec0c0 | |||
53a869b757 | |||
eec2c38a68 | |||
401d7617ef | |||
abd6eace9d | |||
f664eb58c5 | |||
3e3adb4d37 | |||
1d0694df86 | |||
dfdc6fd12c | |||
49997e60cb | |||
1ad63a6a32 | |||
6d23df2c7c | |||
9a55bbdb44 | |||
ab148aeed8 | |||
d1ec5dc089 | |||
c4b1566ba3 | |||
d91f8fa655 | |||
7f636dbfc2 | |||
93c821aaa3 | |||
a752b15921 | |||
3a98d7af18 | |||
eaf59d5a19 | |||
70da0c2e40 | |||
c97caa6e10 | |||
c092892488 | |||
001d9d3d20 | |||
2c421d48fa | |||
f585f26266 | |||
396157deda | |||
f516926f00 | |||
a7b7f3cde9 | |||
22db79aefa | |||
2cd07abca9 | |||
fcab3ec990 | |||
9065d4ba86 | |||
ed96f9b209 | |||
f567a89dae | |||
00c86b7cb1 | |||
74be9ab5ce | |||
5813a4319c | |||
e956f23a77 | |||
41b0fe7280 | |||
6cad585bdc | |||
6172bc7312 | |||
a2daef29f9 | |||
e983e2e9cf | |||
a25439cfa1 | |||
3e84d6a2ae | |||
7ca1b85c5e | |||
b18bc7b98f | |||
432671449f | |||
96848398d4 | |||
21865c6224 | |||
b96ba509d0 | |||
f94a7e8890 | |||
2e23418a09 | |||
f3dc56f59a | |||
d822181467 | |||
bc969f78f6 | |||
7b877e2c1d | |||
c0ecf7cf61 | |||
7b33148b75 | |||
b66d7f99a7 | |||
7c3c0b26d1 | |||
46237c3332 | |||
8c228b0d23 | |||
531380d6ab | |||
dbb3171624 | |||
6bd48a48cb | |||
c5e5a17d67 | |||
599b4631a3 | |||
228e9527cb | |||
53ff09969c | |||
d7e6f8cb38 | |||
e99d4ba976 | |||
de717cd225 | |||
779a72ef8c | |||
dae5f94bce | |||
c49d346e37 | |||
7a8d0a10ce | |||
369ec31f0e | |||
0a297ed9ef | |||
30495e6bfe | |||
7101ffa1ae | |||
4e5f42cab6 | |||
9ab902402c | |||
529a51c160 | |||
e55b5c5408 | |||
450dbae8cd | |||
a3bc8d3440 | |||
70e3095864 | |||
02b9e583f2 | |||
400c5e92cb | |||
fcb5eda5d0 | |||
a74561b0e7 | |||
e313180e4d | |||
1fc0731604 | |||
53b70ef104 | |||
41a452d4e8 | |||
3ab18d2861 | |||
2bff92c603 | |||
32ffa2664c | |||
fcd2125678 | |||
635da39bd1 | |||
71e2aa5d2b | |||
21203c2ea6 | |||
9eed60d105 | |||
8f17c81691 | |||
74baebd93e | |||
506f6b1349 | |||
145748a7e0 | |||
7893347e13 | |||
5218c0b187 |
@ -24,7 +24,7 @@ import importlib.metadata
|
||||
|
||||
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
|
||||
|
||||
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
|
||||
CURRENT_LLVM = os.getenv('LLVM_VERSION', 16)
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
|
||||
|
||||
|
||||
|
42
.github/workflows/ci.yml
vendored
42
.github/workflows/ci.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: "${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
@ -36,23 +36,23 @@ jobs:
|
||||
run: make distrib ASAN_BUILD=1 NO_NYX=1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
macos:
|
||||
runs-on: macOS-latest
|
||||
env:
|
||||
AFL_MAP_SIZE: 65536
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: install
|
||||
run: brew install make gcc llvm
|
||||
- name: fix install
|
||||
run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
|
||||
- name: build
|
||||
run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1
|
||||
- name: frida
|
||||
run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
|
||||
- name: force frida test for MacOS
|
||||
run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
|
||||
# macos:
|
||||
# runs-on: macOS-latest
|
||||
# env:
|
||||
# AFL_MAP_SIZE: 65536
|
||||
# AFL_SKIP_CPUFREQ: 1
|
||||
# AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - name: install
|
||||
# run: brew install make gcc llvm
|
||||
# - name: fix install
|
||||
# run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
|
||||
# - name: build
|
||||
# run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1
|
||||
# - name: frida
|
||||
# run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
|
||||
# - name: run tests
|
||||
# run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
|
||||
# - name: force frida test for MacOS
|
||||
# run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
|
||||
|
@ -6,7 +6,7 @@
|
||||
#
|
||||
|
||||
FROM ubuntu:22.04 AS aflplusplus
|
||||
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
|
||||
LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
|
||||
LABEL "about"="AFLplusplus container image"
|
||||
|
||||
### Comment out to enable these features
|
||||
@ -94,4 +94,4 @@ RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
|
||||
RUN echo "set encoding=utf-8" > /root/.vimrc && \
|
||||
echo ". /etc/bash_completion" >> ~/.bashrc && \
|
||||
echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \
|
||||
echo "export PS1='"'[afl++ \h] \w \$ '"'" >> ~/.bashrc
|
||||
echo "export PS1='"'[AFL++ \h] \w \$ '"'" >> ~/.bashrc
|
||||
|
68
GNUmakefile
68
GNUmakefile
@ -39,7 +39,7 @@ ASAN_OPTIONS=detect_leaks=0
|
||||
SYS = $(shell uname -s)
|
||||
ARCH = $(shell uname -m)
|
||||
|
||||
$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
|
||||
$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH))
|
||||
|
||||
ifdef NO_SPLICING
|
||||
override CFLAGS_OPT += -DNO_SPLICING
|
||||
@ -100,8 +100,13 @@ else
|
||||
LDFLAGS += $(SDK_LD)
|
||||
endif
|
||||
|
||||
COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
|
||||
ifneq "$(COMPILER_TYPE)" ""
|
||||
#$(info gcc is being used)
|
||||
CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS = -lkstat -lrt -lsocket -lnsl
|
||||
endif
|
||||
|
||||
@ -145,7 +150,7 @@ else
|
||||
endif
|
||||
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
|
||||
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
# -fstack-protector
|
||||
|
||||
@ -180,13 +185,13 @@ AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
ifneq "$(shell command -v python3m 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
|
||||
PYTHON_INCLUDE := $(shell python3m-config --includes)
|
||||
PYTHON_VERSION := $(strip $(shell python3m --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
|
||||
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
|
||||
PYTHON_LIB := $(shell python3m-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3m-config --ldflags)
|
||||
PYTHON_LIB := $(shell python3m-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -194,13 +199,13 @@ endif
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python3 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
|
||||
PYTHON_INCLUDE := $(shell python3-config --includes)
|
||||
PYTHON_VERSION := $(strip $(shell python3 --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
|
||||
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
|
||||
PYTHON_LIB := $(shell python3-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3-config --ldflags)
|
||||
PYTHON_LIB := $(shell python3-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -209,9 +214,9 @@ endif
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python-config --includes)
|
||||
PYTHON_LIB ?= $(shell python-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
|
||||
PYTHON_INCLUDE := $(shell python-config --includes)
|
||||
PYTHON_LIB := $(shell python-config --ldflags)
|
||||
PYTHON_VERSION := $(strip $(shell python --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -220,9 +225,9 @@ endif
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python3.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
|
||||
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
|
||||
PYTHON_INCLUDE := $(shell python3.7-config --includes)
|
||||
PYTHON_LIB := $(shell python3.7-config --ldflags)
|
||||
PYTHON_VERSION := $(strip $(shell python3.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -231,9 +236,9 @@ endif
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
|
||||
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1))
|
||||
PYTHON_INCLUDE := $(shell python2.7-config --includes)
|
||||
PYTHON_LIB := $(shell python2.7-config --ldflags)
|
||||
PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -313,8 +318,8 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
|
||||
@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"
|
||||
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
|
||||
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-13 and clang-13 or newer, see docs/INSTALL.md"
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM and LLD 11+. More information at instrumentation/README.lto.md on how to build it"
|
||||
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
|
||||
@ -357,7 +362,7 @@ performance-test: source-only
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: the main afl++ binaries and llvm/gcc instrumentation"
|
||||
@echo "all: the main AFL++ binaries and llvm/gcc instrumentation"
|
||||
@echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
|
||||
@echo "source-only: everything for source code fuzzing: nyx_mode, libdislocator, libtokencap"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@ -365,7 +370,7 @@ help:
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything compiled (not downloads when on a checkout)"
|
||||
@echo "deepclean: cleans everything including downloads"
|
||||
@echo "uninstall: uninstall afl++ from the system"
|
||||
@echo "uninstall: uninstall AFL++ from the system"
|
||||
@echo "code-format: format the code, do this before you commit and send a PR please!"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "unit: perform unit tests (based on cmocka and GNU linker)"
|
||||
@ -377,6 +382,7 @@ help:
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo "CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)"
|
||||
@echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
|
||||
@echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
|
||||
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
@ -392,7 +398,7 @@ help:
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
@echo e.g.: make LLVM_CONFIG=llvm-config-16
|
||||
|
||||
.PHONY: test_x86
|
||||
ifndef AFL_NO_X86
|
||||
@ -431,7 +437,7 @@ endif
|
||||
|
||||
.PHONY: ready
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
@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)
|
||||
@ -453,7 +459,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
@ -734,7 +740,7 @@ endif
|
||||
@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"
|
||||
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
|
||||
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-13 and clang-13 or newer, see docs/INSTALL.md"
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
|
||||
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"
|
||||
@ -747,7 +753,7 @@ endif
|
||||
@echo
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .TH $* 8 $(BUILD_DATE) "AFL++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@ -759,8 +765,8 @@ endif
|
||||
@./$* -hh 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
|
||||
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> $@
|
||||
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
@ -175,7 +175,7 @@ all_done: test_build
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "AFL++" > ./$@
|
||||
@echo .SH NAME >> ./$@
|
||||
@echo .B $* >> ./$@
|
||||
@echo >> ./$@
|
||||
@ -187,8 +187,8 @@ all_done: test_build
|
||||
@./$* -h 2>&1 | tail -n +4 >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH AUTHOR >> ./$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
|
||||
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
|
@ -46,10 +46,11 @@ LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[7-9]' && echo 1 || echo 0 )
|
||||
LLVM_TOO_OLD = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[1-9]\.|^1[012]\.' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
|
||||
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_13_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[3-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||
@ -69,6 +70,12 @@ ifeq "$(LLVM_TOO_NEW)" "1"
|
||||
$(warning you are using an in-development llvm version - this might break llvm_mode!)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
$(warning you are using an outdated LLVM version! Please use at least LLVM 13 or newer!)
|
||||
$(shell sleep 2)
|
||||
endif
|
||||
|
||||
# No switching the meaning of LLVM_TOO_OLD
|
||||
LLVM_TOO_OLD=1
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
@ -87,11 +94,6 @@ ifeq "$(LLVM_NEWER_API)" "1"
|
||||
LLVM_STDCXX = c++17
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
|
||||
$(shell sleep 1)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
@ -274,6 +276,11 @@ ifndef LLVM_DEBUG
|
||||
CFLAGS_SAFE += -Wno-deprecated
|
||||
endif
|
||||
|
||||
ifdef CODE_COVERAGE
|
||||
override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1
|
||||
override LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
override CFLAGS += $(CFLAGS_SAFE)
|
||||
|
||||
ifdef AFL_TRACE_PC
|
||||
@ -417,7 +424,7 @@ endif
|
||||
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_10_OK)" "1"
|
||||
ifeq "$(LLVM_13_OK)" "1"
|
||||
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
|
||||
endif
|
||||
|
||||
@ -510,7 +517,7 @@ install: all
|
||||
install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@
|
||||
@echo .TH $* 8 $(BUILD_DATE) "AFL++" > ./$@
|
||||
@echo .SH NAME >> ./$@
|
||||
@printf "%s" ".B $* \- " >> ./$@
|
||||
@./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@
|
||||
@ -524,8 +531,8 @@ install: all
|
||||
@./$* -h 2>&1 | tail -n +4 >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH AUTHOR >> ./$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
|
||||
@echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
|
@ -1,10 +1,10 @@
|
||||
# American Fuzzy Lop plus plus (AFL++)
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
|
||||
|
||||
Release version: [4.06c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release version: [4.07c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.07a
|
||||
GitHub version: 4.08a
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -12,9 +12,9 @@ Repository:
|
||||
AFL++ is maintained by:
|
||||
|
||||
* Marc "van Hauser" Heuse <mh@mh-sec.de>
|
||||
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
|
||||
* Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
* Dominik Maier <mail@dmnk.co>
|
||||
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
|
||||
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
|
||||
|
||||
Originally developed by Michał "lcamtuf" Zalewski.
|
||||
|
6
TODO.md
6
TODO.md
@ -2,9 +2,9 @@
|
||||
|
||||
## Should
|
||||
|
||||
- splicing selection weighted?
|
||||
- support afl_custom_{send,post_process}, persistent and deferred fork
|
||||
server in afl-showmap
|
||||
- afl-crash-analysis
|
||||
- test cmplog for less than 16bit
|
||||
- support persistent and deferred fork server in afl-showmap?
|
||||
- better autodetection of shifting runtime timeout values
|
||||
- Update afl->pending_not_fuzzed for MOpt
|
||||
- afl-plot to support multiple plot_data
|
||||
|
182
afl-cmin
182
afl-cmin
@ -103,9 +103,10 @@ function usage() {
|
||||
" -o dir - output directory for minimized files\n" \
|
||||
"\n" \
|
||||
"Execution control settings:\n" \
|
||||
" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \
|
||||
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||
" -t msec - run time limit for child process (default: none)\n" \
|
||||
" -t msec - run time limit for child process (default: 5000)\n" \
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n" \
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n" \
|
||||
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
|
||||
@ -119,7 +120,6 @@ function usage() {
|
||||
"For additional tips, please consult README.md\n" \
|
||||
"\n" \
|
||||
"Environment variables used:\n" \
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
@ -133,6 +133,8 @@ function usage() {
|
||||
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
|
||||
"printed to stdout\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n"
|
||||
"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -147,7 +149,7 @@ BEGIN {
|
||||
redirected = 0
|
||||
}
|
||||
|
||||
print "corpus minimization tool for afl++ (awk version)\n"
|
||||
print "corpus minimization tool for AFL++ (awk version)\n"
|
||||
|
||||
# defaults
|
||||
extra_par = ""
|
||||
@ -157,13 +159,19 @@ BEGIN {
|
||||
# process options
|
||||
Opterr = 1 # default is to diagnose
|
||||
Optind = 1 # skip ARGV[0]
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) {
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) {
|
||||
if (_go_c == "i") {
|
||||
if (!Optarg) usage()
|
||||
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
in_dir = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "T") {
|
||||
if (!Optarg) usage()
|
||||
if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
threads = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "o") {
|
||||
if (!Optarg) usage()
|
||||
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
@ -232,7 +240,7 @@ BEGIN {
|
||||
} # while options
|
||||
|
||||
if (!mem_limit) mem_limit = "none"
|
||||
if (!timeout) timeout = "none"
|
||||
if (!timeout) timeout = "5000"
|
||||
|
||||
# get program args
|
||||
i = 0
|
||||
@ -251,21 +259,30 @@ BEGIN {
|
||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||
# handle this safely from an awk script.
|
||||
|
||||
if (!ENVIRON["AFL_ALLOW_TMP"]) {
|
||||
dirlist[0] = in_dir
|
||||
dirlist[1] = target_bin
|
||||
dirlist[2] = out_dir
|
||||
dirlist[3] = stdin_file
|
||||
"pwd" | getline dirlist[4] # current directory
|
||||
for (dirind in dirlist) {
|
||||
dir = dirlist[dirind]
|
||||
#if (!ENVIRON["AFL_ALLOW_TMP"]) {
|
||||
# dirlist[0] = in_dir
|
||||
# dirlist[1] = target_bin
|
||||
# dirlist[2] = out_dir
|
||||
# dirlist[3] = stdin_file
|
||||
# "pwd" | getline dirlist[4] # current directory
|
||||
# for (dirind in dirlist) {
|
||||
# dir = dirlist[dirind]
|
||||
#
|
||||
# if (dir ~ /^(\/var)?\/tmp/) {
|
||||
# print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
|
||||
# exit 1
|
||||
# }
|
||||
# }
|
||||
# delete dirlist
|
||||
#}
|
||||
|
||||
if (dir ~ /^(\/var)?\/tmp/) {
|
||||
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
delete dirlist
|
||||
if (threads && stdin_file) {
|
||||
print "[-] Error: -T and -f cannot be used together." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (!threads && !stdin_file && !nyx_mode) {
|
||||
print "[*] Are you aware of the '-T all' parallelize option that improves the speed for large/slow corpuses?"
|
||||
}
|
||||
|
||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||
@ -301,7 +318,9 @@ BEGIN {
|
||||
|
||||
if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) {
|
||||
|
||||
"command -v "target_bin" 2>/dev/null" | getline tnew
|
||||
cmd = "command -v "target_bin" 2>/dev/null"
|
||||
cmd | getline tnew
|
||||
close(cmd)
|
||||
if (!tnew || !exists_and_is_executable(tnew)) {
|
||||
print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
|
||||
exit 1
|
||||
@ -313,6 +332,7 @@ BEGIN {
|
||||
echo "[!] Trying to obtain the map size of the target ..."
|
||||
get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
|
||||
get_map_size | getline mapsize
|
||||
close(get_map_size)
|
||||
if (mapsize && mapsize > 65535 && mapsize < 100000000) {
|
||||
AFL_MAP_SIZE = "AFL_MAP_SIZE="mapsize" "
|
||||
print "[+] Setting "AFL_MAP_SIZE
|
||||
@ -342,12 +362,28 @@ BEGIN {
|
||||
system("rm -rf "trace_dir" 2>/dev/null");
|
||||
system("rm "out_dir"/id[:_]* 2>/dev/null")
|
||||
|
||||
"ls "out_dir"/* 2>/dev/null | wc -l" | getline noofentries
|
||||
cmd = "ls "out_dir"/* 2>/dev/null | wc -l"
|
||||
cmd | getline noofentries
|
||||
close(cmd)
|
||||
if (0 == system( "test -d "out_dir" -a "noofentries" -gt 0" )) {
|
||||
print "[-] Error: directory '"out_dir"' exists and is not empty - delete it first." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (threads) {
|
||||
cmd = "nproc"
|
||||
cmd | getline nproc
|
||||
close(cmd)
|
||||
if (threads == "all") {
|
||||
threads = nproc
|
||||
} else {
|
||||
if (!(threads > 1 && threads <= nproc)) {
|
||||
print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check for the more efficient way to copy files...
|
||||
if (0 != system("mkdir -p -m 0700 "trace_dir)) {
|
||||
print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
|
||||
@ -357,12 +393,14 @@ BEGIN {
|
||||
if (stdin_file) {
|
||||
# truncate input file
|
||||
printf "" > stdin_file
|
||||
close( stdin_file )
|
||||
close(stdin_file)
|
||||
}
|
||||
|
||||
# First we look in PATH
|
||||
if (0 == system("command -v afl-showmap >/dev/null 2>&1")) {
|
||||
"command -v afl-showmap 2>/dev/null" | getline showmap
|
||||
cmd = "command -v afl-showmap 2>/dev/null"
|
||||
cmd | getline showmap
|
||||
close(cmd)
|
||||
} else {
|
||||
# then we look in the current directory
|
||||
if (0 == system("test -x ./afl-showmap")) {
|
||||
@ -384,7 +422,9 @@ BEGIN {
|
||||
# yuck, gnu stat is option incompatible to bsd stat
|
||||
# we use a heuristic to differentiate between
|
||||
# GNU stat and other stats
|
||||
"stat --version 2>/dev/null" | getline statversion
|
||||
cmd = "stat --version 2>/dev/null"
|
||||
cmd | getline statversion
|
||||
close(cmd)
|
||||
if (statversion ~ /GNU coreutils/) {
|
||||
stat_format = "-c '%s %n'" # GNU
|
||||
} else {
|
||||
@ -403,6 +443,7 @@ BEGIN {
|
||||
infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
|
||||
i++
|
||||
}
|
||||
close(cmdline)
|
||||
in_count = i
|
||||
|
||||
first_file = infilesSmallToBigFull[0]
|
||||
@ -439,6 +480,7 @@ BEGIN {
|
||||
while ((getline < runtest) > 0) {
|
||||
++first_count
|
||||
}
|
||||
close(runtest)
|
||||
|
||||
if (first_count) {
|
||||
print "[+] OK, "first_count" tuples recorded."
|
||||
@ -457,27 +499,79 @@ BEGIN {
|
||||
# STEP 1: Collecting traces #
|
||||
#############################
|
||||
|
||||
if (threads) {
|
||||
|
||||
inputsperfile = int(in_count / threads)
|
||||
if (in_count % threads) {
|
||||
inputsperfile++;
|
||||
}
|
||||
|
||||
cnt = 0;
|
||||
tmpfile=out_dir "/.filelist"
|
||||
for (instance = 1; instance < threads; instance++) {
|
||||
for (i = 0; i < inputsperfile; i++) {
|
||||
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
for (; cnt < in_count; cnt++) {
|
||||
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
|
||||
|
||||
cur = 0;
|
||||
if (!stdin_file) {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
|
||||
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
} else {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) {
|
||||
print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..."
|
||||
if (threads > 1) {
|
||||
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
system("rmdir "out_dir)
|
||||
print "[*] Creating " threads " parallel tasks with about " inputsperfile " items each."
|
||||
for (i = 1; i <= threads; i++) {
|
||||
|
||||
if (!stdin_file) {
|
||||
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &"
|
||||
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &")
|
||||
} else {
|
||||
stdin_file=tmpfile"."i".stdin"
|
||||
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &"
|
||||
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &")
|
||||
}
|
||||
}
|
||||
exit retval
|
||||
print "[*] Waiting for parallel tasks to complete ..."
|
||||
# wait for all processes to finish
|
||||
ok=0
|
||||
while (ok < threads) {
|
||||
ok=0
|
||||
for (i = 1; i <= threads; i++) {
|
||||
if (system("test -f "tmpfile"."i".done") == 0) {
|
||||
ok++
|
||||
}
|
||||
}
|
||||
}
|
||||
print "[*] Done!"
|
||||
system("rm -f "tmpfile"*")
|
||||
} else {
|
||||
if (!stdin_file) {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
|
||||
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
} else {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) {
|
||||
print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..."
|
||||
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
system("rmdir "out_dir)
|
||||
}
|
||||
exit retval
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#######################################################
|
||||
@ -501,6 +595,15 @@ BEGIN {
|
||||
else { print " Processing file "cur"/"in_count }
|
||||
# create path for the trace file from afl-showmap
|
||||
tracefile_path = trace_dir"/"fn
|
||||
# ensure the file size is not zero
|
||||
cmd = "du -b "tracefile_path
|
||||
"ls -l "tracefile_path
|
||||
cmd | getline output
|
||||
close(cmd)
|
||||
split(output, result, "\t")
|
||||
if (result[1] == 0) {
|
||||
print "[!] WARNING: file "fn" is crashing the target, ignoring..."
|
||||
}
|
||||
# gather all keys, and count them
|
||||
while ((getline line < tracefile_path) > 0) {
|
||||
key = line
|
||||
@ -562,6 +665,7 @@ BEGIN {
|
||||
}
|
||||
}
|
||||
close(sortedKeys)
|
||||
print ""
|
||||
print "[+] Found "tuple_count" unique tuples across "in_count" files."
|
||||
|
||||
if (out_count == 1) {
|
||||
|
116
afl-cmin.bash
116
afl-cmin.bash
@ -7,6 +7,8 @@
|
||||
#
|
||||
# Copyright 2014, 2015 Google Inc. All rights reserved.
|
||||
#
|
||||
# Copyright 2019-2023 AFLplusplus
|
||||
#
|
||||
# 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:
|
||||
@ -36,7 +38,7 @@
|
||||
# array sizes.
|
||||
#
|
||||
|
||||
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
|
||||
echo "corpus minimization tool for afl-fuzz"
|
||||
echo
|
||||
|
||||
#########
|
||||
@ -46,14 +48,14 @@ echo
|
||||
# Process command-line options...
|
||||
|
||||
MEM_LIMIT=none
|
||||
TIMEOUT=none
|
||||
TIMEOUT=5000
|
||||
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN F_ARG \
|
||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE T_ARG
|
||||
|
||||
export AFL_QUIET=1
|
||||
|
||||
while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
|
||||
while getopts "+i:o:f:m:t:T:eOQUAChXY" opt; do
|
||||
|
||||
case "$opt" in
|
||||
|
||||
@ -69,6 +71,7 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
|
||||
;;
|
||||
"f")
|
||||
STDIN_FILE="$OPTARG"
|
||||
F_ARG=1
|
||||
;;
|
||||
"m")
|
||||
MEM_LIMIT="$OPTARG"
|
||||
@ -106,6 +109,9 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do
|
||||
EXTRA_PAR="$EXTRA_PAR -U"
|
||||
UNICORN_MODE=1
|
||||
;;
|
||||
"T")
|
||||
T_ARG="$OPTARG"
|
||||
;;
|
||||
"?")
|
||||
exit 1
|
||||
;;
|
||||
@ -130,9 +136,10 @@ Required parameters:
|
||||
|
||||
Execution control settings:
|
||||
|
||||
-f file - location read by the fuzzed program (stdin)
|
||||
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
||||
-t msec - run time limit for child process (none)
|
||||
-T tasks - how many parallel processes to create (default=1, "all"=nproc)
|
||||
-f file - location read by the fuzzed program (default: stdin)
|
||||
-m megs - memory limit for child process (default=$MEM_LIMIT MB)
|
||||
-t msec - run time limit for child process (default: 5000ms)
|
||||
-O - use binary-only instrumentation (FRIDA mode)
|
||||
-Q - use binary-only instrumentation (QEMU mode)
|
||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||
@ -151,6 +158,8 @@ AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
|
||||
AFL_NO_FORKSRV: run target via execve instead of using the forkserver
|
||||
AFL_PATH: last resort location to find the afl-showmap binary
|
||||
AFL_SKIP_BIN_CHECK: skip check for target binary
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)
|
||||
AFL_PYTHON_MODULE: custom mutator library (post_process and send)
|
||||
_EOF_
|
||||
exit 1
|
||||
fi
|
||||
@ -197,6 +206,11 @@ fi
|
||||
|
||||
# Check for obvious errors.
|
||||
|
||||
if [ ! "$T_ARG" = "" -a -n "$F_ARG" -a ! "$NYX_MODE" == 1 ]; then
|
||||
echo "[-] Error: -T and -f can not be used together." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! "$MEM_LIMIT" = "none" ]; then
|
||||
|
||||
if [ "$MEM_LIMIT" -lt "5" ]; then
|
||||
@ -231,7 +245,7 @@ if [ "$NYX_MODE" = "" ]; then
|
||||
|
||||
fi
|
||||
|
||||
grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && {
|
||||
grep -aq AFL_DUMP_MAP_SIZE "$TARGET_BIN" && {
|
||||
echo "[!] Trying to obtain the map size of the target ..."
|
||||
MAPSIZE=`AFL_DUMP_MAP_SIZE=1 "./$TARGET_BIN" 2>/dev/null`
|
||||
test -n "$MAPSIZE" && {
|
||||
@ -297,14 +311,34 @@ if [ ! -x "$SHOWMAP" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
THREADS=
|
||||
if [ ! "$T_ARG" = "" ]; then
|
||||
if [ "$T_ARG" = "all" ]; then
|
||||
THREADS=$(nproc)
|
||||
else
|
||||
if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then
|
||||
THREADS=$T_ARG
|
||||
else
|
||||
echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -z "$F_ARG" ]; then
|
||||
echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
|
||||
fi
|
||||
fi
|
||||
|
||||
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
|
||||
|
||||
if [ "$IN_COUNT" = "0" ]; then
|
||||
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
|
||||
echo "[-] Hmm, no inputs in the target directory. Nothing to be done."
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?"
|
||||
echo "[+] Found $IN_COUNT files for minimizing."
|
||||
|
||||
FIRST_FILE=`ls "$IN_DIR" | head -1`
|
||||
|
||||
# Make sure that we're not dealing with a directory.
|
||||
@ -353,6 +387,18 @@ else
|
||||
|
||||
fi
|
||||
|
||||
TMPFILE=$OUT_DIR/.list.$$
|
||||
if [ ! "$THREADS" = "" ]; then
|
||||
ls -- "$IN_DIR" > $TMPFILE 2>/dev/null
|
||||
IN_COUNT=$(cat $TMPFILE | wc -l)
|
||||
SPLIT=$(($IN_COUNT / $THREADS))
|
||||
if [ "$(($IN_COUNT % $THREADS))" -gt 0 ]; then
|
||||
SPLIT=$(($SPLIT + 1))
|
||||
fi
|
||||
echo "[+] Splitting workload into $THREADS tasks with $SPLIT items on average each."
|
||||
split -l $SPLIT $TMPFILE $TMPFILE.
|
||||
fi
|
||||
|
||||
# Let's roll!
|
||||
|
||||
#############################
|
||||
@ -361,6 +407,7 @@ fi
|
||||
|
||||
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
||||
|
||||
if [ "$THREADS" = "" ]; then
|
||||
(
|
||||
|
||||
CUR=0
|
||||
@ -384,17 +431,58 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
done
|
||||
|
||||
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
)
|
||||
|
||||
echo
|
||||
else
|
||||
|
||||
PIDS=
|
||||
CNT=0
|
||||
for inputs in $(ls ${TMPFILE}.*); do
|
||||
|
||||
(
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
cat $inputs | while read -r fn; do
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
|
||||
|
||||
done
|
||||
|
||||
else
|
||||
|
||||
STDIN_FILE="$inputs.$$"
|
||||
cat $inputs | while read -r fn; do
|
||||
|
||||
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
) &
|
||||
|
||||
PIDS="$PIDS $!"
|
||||
done
|
||||
|
||||
echo "[+] Waiting for running tasks IDs:$PIDS"
|
||||
wait
|
||||
echo "[+] all $THREADS running tasks completed."
|
||||
rm -f ${TMPFILE}*
|
||||
|
||||
#echo trace dir files: $(ls $TRACE_DIR/*|wc -l)
|
||||
|
||||
fi
|
||||
|
||||
|
||||
##########################
|
||||
# STEP 2: SORTING TUPLES #
|
||||
@ -435,6 +523,8 @@ ls -rS "$IN_DIR" | while read -r fn; do
|
||||
|
||||
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
|
||||
|
||||
test -s "$TRACE_DIR/$fn" || echo Warning: $fn is ignored because of crashing the target
|
||||
|
||||
done
|
||||
|
||||
echo
|
||||
|
15
afl-plot
15
afl-plot
@ -75,8 +75,17 @@ outputdir=`get_abs_path "$2"`
|
||||
|
||||
if [ ! -f "$inputdir/plot_data" ]; then
|
||||
|
||||
echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
|
||||
exit 1
|
||||
if [ -f "$inputdir/default/plot_data" ]; then
|
||||
|
||||
echo "[-] Error: input directory is not valid (missing 'plot_data'), likely you mean $inputdir/default?" 1>&2
|
||||
exit 1
|
||||
|
||||
else
|
||||
|
||||
echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
@ -141,7 +150,7 @@ set output '$outputdir/high_freq.png'
|
||||
$GNUPLOT_SETUP
|
||||
|
||||
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'corpus count' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:3 with filledcurve x1 title 'current fuzz item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
|
||||
'' using 1:3 with filledcurve x1 title 'current item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
|
||||
'' using 1:5 with lines title 'pending items' linecolor rgb '#0090ff' linewidth 3, \\
|
||||
'' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
|
||||
'' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3
|
||||
|
@ -110,7 +110,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
sysctl kern.sysv.shmall=131072000
|
||||
echo Settings applied.
|
||||
echo
|
||||
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
|
||||
if $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ; then
|
||||
echo
|
||||
echo Unloading the default crash reporter
|
||||
SL=/System/Library; PL=com.apple.ReportCrash
|
||||
@ -119,6 +119,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
echo
|
||||
fi
|
||||
echo It is recommended to disable System Integrity Protection for increased performance.
|
||||
echo See: https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
|
@ -88,6 +88,7 @@ TOTAL_TIME=0
|
||||
TOTAL_EXECS=0
|
||||
TOTAL_EPS=0
|
||||
TOTAL_CRASHES=0
|
||||
TOTAL_HANGS=0
|
||||
TOTAL_PFAV=0
|
||||
TOTAL_PENDING=0
|
||||
|
||||
@ -190,6 +191,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
|
||||
TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
|
||||
TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
|
||||
TOTAL_HANGS=$((TOTAL_HANGS + saved_hangs))
|
||||
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
|
||||
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
|
||||
|
||||
@ -301,6 +303,7 @@ if [ "$ALIVE_CNT" -gt "1" ]; then
|
||||
fi
|
||||
|
||||
echo " Crashes saved : $TOTAL_CRASHES"
|
||||
echo " Hangs saved : $TOTAL_HANGS"
|
||||
echo "Cycles without finds : $TOTAL_WCOP"
|
||||
echo " Time without finds : $TOTAL_LAST_FIND"
|
||||
echo
|
||||
|
@ -11,29 +11,6 @@ The `./examples` folder contains examples for custom mutators in python and C.
|
||||
|
||||
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
|
||||
|
||||
## The AFL++ grammar agnostic grammar mutator
|
||||
|
||||
In `./autotokens` you find a token-level fuzzer that does not need to know
|
||||
anything about the grammar of an input as long as it is in ascii and allows
|
||||
whitespace.
|
||||
It is very fast and effective.
|
||||
|
||||
If you are looking for an example of how to effectively create a custom
|
||||
mutator take a look at this one.
|
||||
|
||||
## The AFL++ Grammar Mutator
|
||||
|
||||
If you use git to clone AFL++, then the following will incorporate our
|
||||
excellent grammar custom mutator:
|
||||
|
||||
```sh
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
Read the README in the [Grammar-Mutator] repository on how to use it.
|
||||
|
||||
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
||||
|
||||
## Production-Ready Custom Mutators
|
||||
|
||||
This directory holds ready to use custom mutators.
|
||||
@ -47,6 +24,42 @@ and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
|
||||
|
||||
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
|
||||
|
||||
### The AFL++ grammar agnostic grammar mutator
|
||||
|
||||
In `./autotokens` you find a token-level fuzzer that does not need to know
|
||||
anything about the grammar of an input as long as it is in ascii and allows
|
||||
whitespace.
|
||||
It is very fast and effective.
|
||||
|
||||
If you are looking for an example of how to effectively create a custom
|
||||
mutator take a look at this one.
|
||||
|
||||
### The AFL++ Grammar Mutator
|
||||
|
||||
If you use git to clone AFL++, then the following will incorporate our
|
||||
excellent grammar custom mutator:
|
||||
|
||||
```sh
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
Read the README in the [Grammar-Mutator] repository on how to use it.
|
||||
|
||||
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
||||
|
||||
Note that this custom mutator is not very good though!
|
||||
|
||||
### Other Mutators
|
||||
|
||||
atnwalk and gramatron are grammar custom mutators. Example grammars are
|
||||
provided.
|
||||
|
||||
honggfuzz, libfuzzer and libafl are partial implementations based on the
|
||||
mutator implementations of the respective fuzzers.
|
||||
More for playing than serious usage.
|
||||
|
||||
radamsa is slow and not very good.
|
||||
|
||||
## 3rd Party Custom Mutators
|
||||
|
||||
### Superion Mutators
|
||||
@ -57,14 +70,17 @@ requires cmake (among other things):
|
||||
|
||||
### libprotobuf Mutators
|
||||
|
||||
There are two WIP protobuf projects, that require work to be working though:
|
||||
There are three WIP protobuf projects, that require work to be working though:
|
||||
|
||||
ASN.1 example:
|
||||
[https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator](https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator)
|
||||
|
||||
transforms protobuf raw:
|
||||
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
|
||||
[https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
||||
|
||||
has a transform function you need to fill for your protobuf format, however
|
||||
needs to be ported to the updated AFL++ custom mutator API (not much work):
|
||||
https://github.com/thebabush/afl-libprotobuf-mutator
|
||||
[https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
||||
|
||||
same as above but is for current AFL++:
|
||||
https://github.com/P1umer/AFLplusplus-protobuf-mutator
|
||||
[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
|
10
custom_mutators/aflpp/Makefile
Normal file
10
custom_mutators/aflpp/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
|
||||
|
||||
all: aflpp-mutator.so
|
||||
|
||||
aflpp-mutator.so: aflpp.c
|
||||
$(CC) $(CFLAGS) -I../../include -I. -shared -o aflpp-mutator.so aflpp.c ../../src/afl-performance.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ *.so core
|
8
custom_mutators/aflpp/README.md
Normal file
8
custom_mutators/aflpp/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# custum mutator: AFL++
|
||||
|
||||
this is the AFL++ havoc mutator as a custom mutator module for AFL++.
|
||||
|
||||
just type `make` to build
|
||||
|
||||
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/aflpp/aflpp-mutator.so afl-fuzz ...```
|
||||
|
89
custom_mutators/aflpp/aflpp.c
Normal file
89
custom_mutators/aflpp/aflpp.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include "afl-mutations.h"
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
u8 *buf;
|
||||
u32 buf_size;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
(void)seed;
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ((data->buf = malloc(MAX_FILE)) == NULL) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
|
||||
data->buf_size = MAX_FILE;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/* here we run the AFL++ mutator, which is the best! */
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
if (max_size > data->buf_size) {
|
||||
|
||||
u8 *ptr = realloc(data->buf, max_size);
|
||||
|
||||
if (ptr) {
|
||||
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
|
||||
data->buf = ptr;
|
||||
data->buf_size = max_size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 havoc_steps = 1 + rand_below(data->afl, 16);
|
||||
|
||||
/* set everything up, costly ... :( */
|
||||
memcpy(data->buf, buf, buf_size);
|
||||
|
||||
/* the mutation */
|
||||
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
|
||||
false, true, add_buf, add_buf_size, max_size);
|
||||
|
||||
/* return size of mutated data */
|
||||
*out_buf = data->buf;
|
||||
return out_buf_len;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
10
custom_mutators/aflpp/standalone/Makefile
Normal file
10
custom_mutators/aflpp/standalone/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
CFLAGS = -O3 -funroll-loops -fPIC
|
||||
|
||||
all: aflpp-standalone
|
||||
|
||||
aflpp-standalone: aflpp-standalone.c
|
||||
$(CC) $(CFLAGS) -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ aflpp-standalone core
|
10
custom_mutators/aflpp/standalone/README.md
Normal file
10
custom_mutators/aflpp/standalone/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# AFL++ standalone mutator
|
||||
|
||||
this is the AFL++ havoc mutator as a standalone mutator
|
||||
|
||||
just type `make` to build.
|
||||
|
||||
```
|
||||
aflpp-standalone inputfile outputfile [splicefile]
|
||||
```
|
||||
|
165
custom_mutators/aflpp/standalone/aflpp-standalone.c
Normal file
165
custom_mutators/aflpp/standalone/aflpp-standalone.c
Normal file
@ -0,0 +1,165 @@
|
||||
#include "afl-mutations.h"
|
||||
|
||||
s8 interesting_8[] = {INTERESTING_8};
|
||||
s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
|
||||
s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
u8 *buf;
|
||||
u32 buf_size;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
(void)seed;
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ((data->buf = malloc(1024*1024)) == NULL) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
|
||||
data->buf_size = 1024*1024;
|
||||
|
||||
}
|
||||
|
||||
/* fake AFL++ state */
|
||||
data->afl = calloc(1, sizeof(afl_state_t));
|
||||
data->afl->queue_cycle = 1;
|
||||
data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
|
||||
rand_set_seed(data->afl, getpid());
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/* here we run the AFL++ mutator, which is the best! */
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
if (max_size > data->buf_size) {
|
||||
|
||||
u8 *ptr = realloc(data->buf, max_size);
|
||||
|
||||
if (ptr) {
|
||||
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
|
||||
data->buf = ptr;
|
||||
data->buf_size = max_size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 havoc_steps = 1 + rand_below(data->afl, 16);
|
||||
|
||||
/* set everything up, costly ... :( */
|
||||
memcpy(data->buf, buf, buf_size);
|
||||
|
||||
/* the mutation */
|
||||
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
|
||||
false, true, add_buf, add_buf_size, max_size);
|
||||
|
||||
/* return size of mutated data */
|
||||
*out_buf = data->buf;
|
||||
return out_buf_len;
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
|
||||
printf("Syntax: %s [-v] [inputfile [outputfile [splicefile]]]\n\n", argv[0]);
|
||||
printf("Reads a testcase from stdin when no input file (or '-') is specified,\n");
|
||||
printf("mutates according to AFL++'s mutation engine, and write to stdout when '-' or\n");
|
||||
printf("no output filename is given. As an optional third parameter you can give a file\n");
|
||||
printf("for splicing. Maximum input and output length is 1MB.\n");
|
||||
printf("The -v verbose option prints debug output to stderr.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *in = stdin, *out = stdout, *splice = NULL;
|
||||
unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL;
|
||||
int verbose = 0, splicelen = 0;
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
|
||||
verbose = 1;
|
||||
argc--;
|
||||
argv++;
|
||||
fprintf(stderr, "Verbose active\n");
|
||||
}
|
||||
|
||||
my_mutator_t *data = afl_custom_init(NULL, 0);
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "-") != 0) {
|
||||
if ((in = fopen(argv[1], "r")) == NULL) {
|
||||
perror(argv[1]);
|
||||
return -1;
|
||||
}
|
||||
if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
|
||||
}
|
||||
|
||||
size_t inlen = fread(inbuf, 1, 1024*1024, in);
|
||||
|
||||
if (!inlen) {
|
||||
fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc > 2 && strcmp(argv[2], "-") != 0) {
|
||||
if ((out = fopen(argv[2], "w")) == NULL) {
|
||||
perror(argv[2]);
|
||||
return -1;
|
||||
}
|
||||
if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
if ((splice = fopen(argv[3], "r")) == NULL) {
|
||||
perror(argv[3]);
|
||||
return -1;
|
||||
}
|
||||
if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
|
||||
splicebuf = malloc(1024*1024);
|
||||
size_t splicelen = fread(splicebuf, 1, 1024*1024, splice);
|
||||
if (!splicelen) {
|
||||
fprintf(stderr, "Error: empty file %s\n", argv[3]);
|
||||
return -1;
|
||||
}
|
||||
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
|
||||
}
|
||||
|
||||
if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
|
||||
unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf, splicelen, 1024*1024);
|
||||
|
||||
if (outlen == 0 || !outbuf) {
|
||||
fprintf(stderr, "Error: no mutation data returned.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose) fprintf(stderr, "Mutation output length: %zu\n", outlen);
|
||||
|
||||
if (fwrite(outbuf, 1, outlen, out) != outlen) {
|
||||
fprintf(stderr, "Warning: incomplete write.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
22
custom_mutators/aflpp_tritondse/README.md
Normal file
22
custom_mutators/aflpp_tritondse/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# An AFL++ custom mutator using TritonDSE
|
||||
|
||||
## Installing the requirements
|
||||
|
||||
`pip3 install tritondse`
|
||||
|
||||
## How to run with an example
|
||||
|
||||
```
|
||||
../../afl-cc -o ../../test-instr ../../test-instr.c
|
||||
mkdir -p in
|
||||
echo aaaa > in/in
|
||||
AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
|
||||
```
|
||||
|
||||
Note that this custom mutator works differently, new finds are synced
|
||||
after 10-60 seconds to the fuzzing instance. This is necessary because only
|
||||
C/C++ custom mutators have access to the internal AFL++ state.
|
||||
|
||||
Note that you should run first with `AFL_DEBUG` for 5-10 minutes and see if
|
||||
all important libraries and syscalls are hooked (look at `WARNING` and `CRITICAL`
|
||||
output during the run, best use with `AFL_NO_UI=1`)
|
220
custom_mutators/aflpp_tritondse/aflpp_tritondse.py
Normal file
220
custom_mutators/aflpp_tritondse/aflpp_tritondse.py
Normal file
@ -0,0 +1,220 @@
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
import hashlib
|
||||
|
||||
from tritondse import CleLoader
|
||||
from tritondse import CompositeData
|
||||
from tritondse import Config
|
||||
from tritondse import CoverageStrategy
|
||||
from tritondse import ProcessState
|
||||
from tritondse import Program
|
||||
from tritondse import Seed
|
||||
from tritondse import SeedFormat
|
||||
from tritondse import SymbolicExecutor
|
||||
from tritondse import SymbolicExplorator
|
||||
|
||||
is_debug = False
|
||||
out_path = ""
|
||||
input_file = None
|
||||
prog = None
|
||||
config = None
|
||||
dse = None
|
||||
cycle = 0
|
||||
count = 0
|
||||
finding = 0
|
||||
hashes = set()
|
||||
format = SeedFormat.RAW
|
||||
|
||||
def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
|
||||
global count
|
||||
global hashes
|
||||
global finding
|
||||
if se.seed.hash not in hashes:
|
||||
hashes.add(se.seed.hash)
|
||||
finding = 1
|
||||
filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash
|
||||
if not os.path.exists(filename):
|
||||
if is_debug:
|
||||
print('Creating queue input ' + filename)
|
||||
with open(filename, 'wb') as file:
|
||||
if input_file:
|
||||
file.write(se.seed.content.files[input_file])
|
||||
else:
|
||||
file.write(se.seed.content)
|
||||
count += 1
|
||||
#if input_file:
|
||||
# if is_debug:
|
||||
# print('Writing to ' + input_file + ' the content: ' + str(se.seed.content))
|
||||
# with open(input_file, 'wb') as file:
|
||||
# file.write(se.seed.content)
|
||||
|
||||
|
||||
#def rtn_open(se: SymbolicExecutor, pstate: ProcessState, pc):
|
||||
# """
|
||||
# The open behavior.
|
||||
# """
|
||||
# logging.debug('open hooked')
|
||||
#
|
||||
# # Get arguments
|
||||
# arg0 = pstate.get_argument_value(0) # const char *pathname
|
||||
# flags = pstate.get_argument_value(1) # int flags
|
||||
# mode = pstate.get_argument_value(2) # int mode
|
||||
# arg0s = pstate.memory.read_string(arg0)
|
||||
#
|
||||
# # Concretize the whole path name
|
||||
# pstate.concretize_memory_bytes(arg0, len(arg0s)+1) # Concretize the whole string + \0
|
||||
#
|
||||
# # We use flags as concrete value
|
||||
# pstate.concretize_argument(1)
|
||||
#
|
||||
# # Use the flags to open the file in the write mode.
|
||||
# mode = ""
|
||||
# if (flags & 0xFF) == 0x00: # O_RDONLY
|
||||
# mode = "r"
|
||||
# elif (flags & 0xFF) == 0x01: # O_WRONLY
|
||||
# mode = "w"
|
||||
# elif (flags & 0xFF) == 0x02: # O_RDWR
|
||||
# mode = "r+"
|
||||
#
|
||||
# if (flags & 0x0100): # O_CREAT
|
||||
# mode += "x"
|
||||
# if (flags & 0x0200): # O_APPEND
|
||||
# mode = "a" # replace completely value
|
||||
#
|
||||
# if se.seed.is_file_defined(arg0s) and "r" in mode: # input file and opened in reading
|
||||
# logging.info(f"opening an input file: {arg0s}")
|
||||
# # Program is opening an input
|
||||
# data = se.seed.get_file_input(arg0s)
|
||||
# filedesc = pstate.create_file_descriptor(arg0s, io.BytesIO(data))
|
||||
# fd = filedesc.id
|
||||
# else:
|
||||
# # Try to open it as a regular file
|
||||
# try:
|
||||
# fd = open(arg0s, mode) # use the mode here
|
||||
# filedesc = pstate.create_file_descriptor(arg0s, fd)
|
||||
# fd = filedesc.id
|
||||
# except Exception as e:
|
||||
# logging.debug(f"Failed to open {arg0s} {e}")
|
||||
# fd = pstate.minus_one
|
||||
#
|
||||
# pstate.write_register("rax", fd) # write the return value
|
||||
# pstate.cpu.program_counter = pstate.pop_stack_value() # pop the return value
|
||||
# se.skip_instruction() # skip the current instruction so that the engine go straight fetching the next instruction
|
||||
|
||||
|
||||
def init(seed):
|
||||
global config
|
||||
global dse
|
||||
global format
|
||||
global input_file
|
||||
global is_debug
|
||||
global out_path
|
||||
global prog
|
||||
# Load the program (LIEF-based program loader).
|
||||
prog = CleLoader(os.environ['AFL_CUSTOM_INFO_PROGRAM'])
|
||||
# Process other configuration environment variables.
|
||||
argv = None
|
||||
try:
|
||||
foo = os.environ['AFL_DEBUG']
|
||||
is_debug = True
|
||||
except KeyError:
|
||||
pass
|
||||
if is_debug:
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
else:
|
||||
logging.basicConfig(level=logging.CRITICAL)
|
||||
try:
|
||||
foo = os.environ['AFL_CUSTOM_INFO_OUT']
|
||||
out_path = foo + '/../tritondse/queue'
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
foo = os.environ['AFL_CUSTOM_INFO_PROGRAM_INPUT']
|
||||
input_file = foo
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
argv_list = os.environ['AFL_CUSTOM_INFO_PROGRAM_ARGV']
|
||||
argv_tmp = [ os.environ['AFL_CUSTOM_INFO_PROGRAM'] ]
|
||||
argv_tmp += argv_list.split()
|
||||
argv = []
|
||||
# now check for @@
|
||||
for item in argv_tmp:
|
||||
if "@@" in item:
|
||||
input_file = out_path + '/../.input'
|
||||
argv.append(input_file)
|
||||
else:
|
||||
argv.append(item)
|
||||
except KeyError:
|
||||
pass
|
||||
# Create the output directory
|
||||
os.makedirs(out_path, exist_ok=True)
|
||||
# Debug
|
||||
if is_debug:
|
||||
print('DEBUG target: ' + os.environ['AFL_CUSTOM_INFO_PROGRAM'])
|
||||
if argv:
|
||||
print('DEBUG argv: ')
|
||||
print(argv)
|
||||
if input_file:
|
||||
print('DEBUG input_file: ' + input_file)
|
||||
print('DEBUG out_path: ' + out_path)
|
||||
print('')
|
||||
if input_file:
|
||||
format = SeedFormat.COMPOSITE
|
||||
# Now set up TritonDSE
|
||||
config = Config(coverage_strategy = CoverageStrategy.PATH,
|
||||
debug = is_debug,
|
||||
pipe_stdout = is_debug,
|
||||
pipe_stderr = is_debug,
|
||||
execution_timeout = 1,
|
||||
program_argv = argv,
|
||||
smt_timeout= 50,
|
||||
seed_format = format)
|
||||
# Create an instance of the Symbolic Explorator
|
||||
dse = SymbolicExplorator(config, prog)
|
||||
# Add callbacks.
|
||||
dse.callback_manager.register_pre_execution_callback(pre_exec_hook)
|
||||
#dse.callback_manager.register_function_callback("open", rtn_open)
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
global finding
|
||||
finding = 1
|
||||
while finding == 1:
|
||||
finding = 0
|
||||
dse.step()
|
||||
return b""
|
||||
|
||||
|
||||
def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
global cycle
|
||||
global dse
|
||||
# Add seed to the worklist.
|
||||
with open(filename_new_queue, "rb") as file:
|
||||
data = file.read()
|
||||
hash = hashlib.md5(data).hexdigest()
|
||||
if hash not in hashes:
|
||||
hashes.add(hash)
|
||||
if is_debug:
|
||||
print("NEW FILE " + filename_new_queue + " hash " + hash + " count " + str(cycle))
|
||||
cycle += 1
|
||||
if input_file:
|
||||
seed = Seed(CompositeData(files={"stdin": b"", # nothing on stdin
|
||||
input_file: data}))
|
||||
else:
|
||||
seed = Seed(data)
|
||||
dse.add_input_seed(seed)
|
||||
# Start exploration!
|
||||
#dse.step()
|
||||
#dse.explore()
|
||||
pass
|
||||
|
||||
|
||||
# we simulate just doing one single fuzz in the custom mutator
|
||||
def fuzz_count(buf):
|
||||
return 1
|
||||
|
||||
|
||||
def splice_optout():
|
||||
pass
|
7
custom_mutators/atnwalk/Makefile
Normal file
7
custom_mutators/atnwalk/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: atnwalk.so
|
||||
|
||||
atnwalk.so: atnwalk.c
|
||||
$(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o *~ core
|
43
custom_mutators/atnwalk/README.md
Normal file
43
custom_mutators/atnwalk/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations
|
||||
|
||||
This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets.
|
||||
|
||||
Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running.
|
||||
|
||||
## Build
|
||||
|
||||
Just type `make` to build `atnwalk.so`.
|
||||
|
||||
## Run
|
||||
|
||||
**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
|
||||
|
||||
```bash
|
||||
# create the required a random seed first
|
||||
mkdir -p ~/campaign/example/seeds
|
||||
cd ~/campaign/example/seeds
|
||||
head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded
|
||||
|
||||
# create the required atnwalk directory and copy the seed
|
||||
cd ../
|
||||
mkdir -p atnwalk/in
|
||||
cp ./seeds/seed.encoded atnwalk/in/seed
|
||||
cd atnwalk
|
||||
|
||||
# assign to a single core when benchmarking it, change the CPU number as required
|
||||
CPU_ID=0
|
||||
|
||||
# start the ATNwalk server
|
||||
nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 &
|
||||
|
||||
# start AFL++ with ATNwalk
|
||||
AFL_SKIP_CPUFREQ=1 \
|
||||
AFL_DISABLE_TRIM=1 \
|
||||
AFL_CUSTOM_MUTATOR_ONLY=1 \
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \
|
||||
AFL_POST_PROCESS_KEEP_ORIGINAL=1 \
|
||||
~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry
|
||||
|
||||
# make sure to kill the ATNwalk server process after you're done
|
||||
kill "$(cat atnwalk.pid)"
|
||||
```
|
539
custom_mutators/atnwalk/atnwalk.c
Normal file
539
custom_mutators/atnwalk/atnwalk.c
Normal file
@ -0,0 +1,539 @@
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BUF_SIZE_INIT 4096
|
||||
#define SOCKET_NAME "./atnwalk.socket"
|
||||
|
||||
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
|
||||
// entry
|
||||
#define ATNWALK_ERRORS_MAX 1
|
||||
|
||||
// how many execution timeouts to tolerate until moving on to the next queue
|
||||
// entry
|
||||
#define EXEC_TIMEOUT_MAX 2
|
||||
|
||||
// handshake constants
|
||||
const uint8_t SERVER_ARE_YOU_ALIVE = 213;
|
||||
const uint8_t SERVER_YES_I_AM_ALIVE = 42;
|
||||
|
||||
// control bits
|
||||
const uint8_t SERVER_CROSSOVER_BIT = 0b00000001;
|
||||
const uint8_t SERVER_MUTATE_BIT = 0b00000010;
|
||||
const uint8_t SERVER_DECODE_BIT = 0b00000100;
|
||||
const uint8_t SERVER_ENCODE_BIT = 0b00001000;
|
||||
|
||||
typedef struct atnwalk_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
uint8_t atnwalk_error_count;
|
||||
uint64_t prev_timeouts;
|
||||
uint32_t prev_hits;
|
||||
uint32_t stage_havoc_cur;
|
||||
uint32_t stage_havoc_max;
|
||||
uint32_t stage_splice_cur;
|
||||
uint32_t stage_splice_max;
|
||||
uint8_t *fuzz_buf;
|
||||
size_t fuzz_size;
|
||||
uint8_t *post_process_buf;
|
||||
size_t post_process_size;
|
||||
|
||||
} atnwalk_mutator_t;
|
||||
|
||||
int read_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||
|
||||
int n;
|
||||
size_t offset = 0;
|
||||
while (offset < buf_size) {
|
||||
|
||||
n = read(fd, buf + offset, buf_size - offset);
|
||||
if (n == -1) { return 0; }
|
||||
offset += n;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||
|
||||
int n;
|
||||
size_t offset = 0;
|
||||
while (offset < buf_size) {
|
||||
|
||||
n = write(fd, buf + offset, buf_size - offset);
|
||||
if (n == -1) { return 0; }
|
||||
offset += n;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void put_uint32(uint8_t *buf, uint32_t val) {
|
||||
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
|
||||
buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
|
||||
buf[3] = (uint8_t)(val & 0x000000ff);
|
||||
|
||||
}
|
||||
|
||||
uint32_t to_uint32(uint8_t *buf) {
|
||||
|
||||
uint32_t val = 0;
|
||||
val |= (((uint32_t)buf[0]) << 24);
|
||||
val |= (((uint32_t)buf[1]) << 16);
|
||||
val |= (((uint32_t)buf[2]) << 8);
|
||||
val |= ((uint32_t)buf[3]);
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
void put_uint64(uint8_t *buf, uint64_t val) {
|
||||
|
||||
buf[0] = (uint8_t)(val >> 56);
|
||||
buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
|
||||
buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
|
||||
buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
|
||||
buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
|
||||
buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
|
||||
buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
|
||||
buf[7] = (uint8_t)(val & 0x00000000000000ff);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this custom mutator
|
||||
*
|
||||
* @param[in] afl a pointer to the internal state object. Can be ignored for
|
||||
* now.
|
||||
* @param[in] seed A seed for this mutator - the same seed should always mutate
|
||||
* in the same way.
|
||||
* @return Pointer to the data object this custom mutator instance should use.
|
||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||
* Return NULL on error.
|
||||
*/
|
||||
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed);
|
||||
atnwalk_mutator_t *data =
|
||||
(atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
data->prev_hits = 0;
|
||||
data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
|
||||
data->fuzz_size = BUF_SIZE_INIT;
|
||||
data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
|
||||
data->post_process_size = BUF_SIZE_INIT;
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
|
||||
const unsigned char *buf, size_t buf_size) {
|
||||
|
||||
// afl_custom_fuzz_count is called exactly once before entering the
|
||||
// 'stage-loop' for the current queue entry thus, we use it to reset the error
|
||||
// count and to initialize stage variables (somewhat not intended by the API,
|
||||
// but still better than rewriting the whole thing to have a custom mutator
|
||||
// stage)
|
||||
data->atnwalk_error_count = 0;
|
||||
data->prev_timeouts = data->afl->total_tmouts;
|
||||
|
||||
// it might happen that on the last execution of the splice stage a new path
|
||||
// is found we need to fix that here and count it
|
||||
if (data->prev_hits) {
|
||||
|
||||
data->afl->stage_finds[STAGE_SPLICE] +=
|
||||
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||
|
||||
}
|
||||
|
||||
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
||||
data->stage_havoc_cur = 0;
|
||||
data->stage_splice_cur = 0;
|
||||
|
||||
// 50% havoc, 50% splice
|
||||
data->stage_havoc_max = data->afl->stage_max >> 1;
|
||||
if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
|
||||
data->stage_splice_max = data->stage_havoc_max;
|
||||
return data->stage_havoc_max + data->stage_splice_max;
|
||||
|
||||
}
|
||||
|
||||
size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
|
||||
|
||||
if (fd_socket != -1) { close(fd_socket); }
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size, uint8_t **out_buf) {
|
||||
|
||||
if (fd_socket != -1) { close(fd_socket); }
|
||||
data->atnwalk_error_count++;
|
||||
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
|
||||
|
||||
data->afl->stage_max = data->afl->stage_cur;
|
||||
|
||||
}
|
||||
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
* (Optional for now. Required in the future)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to input data to be mutated
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
|
||||
* error.
|
||||
* @param[in] add_buf Buffer containing the additional test case
|
||||
* @param[in] add_buf_size Size of the additional test case
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must not
|
||||
* produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
struct sockaddr_un addr;
|
||||
int fd_socket;
|
||||
uint8_t ctrl_buf[8];
|
||||
uint8_t wanted;
|
||||
|
||||
// let's display what's going on in a nice way
|
||||
if (data->stage_havoc_cur == 0) {
|
||||
|
||||
data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
|
||||
|
||||
}
|
||||
|
||||
if (data->stage_havoc_cur == data->stage_havoc_max) {
|
||||
|
||||
data->afl->stage_name = (uint8_t *)"atnwalk - splice";
|
||||
|
||||
}
|
||||
|
||||
// increase the respective havoc or splice counters
|
||||
if (data->stage_havoc_cur < data->stage_havoc_max) {
|
||||
|
||||
data->stage_havoc_cur++;
|
||||
data->afl->stage_cycles[STAGE_HAVOC]++;
|
||||
|
||||
} else {
|
||||
|
||||
// if there is nothing to splice, continue with havoc and skip splicing this
|
||||
// time
|
||||
if (data->afl->ready_for_splicing_count < 1) {
|
||||
|
||||
data->stage_havoc_max = data->afl->stage_max;
|
||||
data->stage_havoc_cur++;
|
||||
data->afl->stage_cycles[STAGE_HAVOC]++;
|
||||
|
||||
} else {
|
||||
|
||||
data->stage_splice_cur++;
|
||||
data->afl->stage_cycles[STAGE_SPLICE]++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// keep track of found new corpus seeds per stage
|
||||
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
|
||||
|
||||
if (data->stage_splice_cur <= 1) {
|
||||
|
||||
data->afl->stage_finds[STAGE_HAVOC] +=
|
||||
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||
|
||||
} else {
|
||||
|
||||
data->afl->stage_finds[STAGE_SPLICE] +=
|
||||
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
|
||||
|
||||
// check whether this input produces a lot of timeouts, if it does then
|
||||
// abandon this queue entry
|
||||
if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
|
||||
|
||||
data->afl->stage_max = data->afl->stage_cur;
|
||||
return fail_gracefully(-1, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// initialize the socket
|
||||
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// ask whether the server is alive
|
||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// see whether the server replies as expected
|
||||
if (!read_all(fd_socket, ctrl_buf, 1) ||
|
||||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// tell the server what we want to do
|
||||
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
|
||||
|
||||
// perform a crossover if we are splicing
|
||||
if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
|
||||
|
||||
// tell the server what we want and how much data will be sent
|
||||
ctrl_buf[0] = wanted;
|
||||
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
|
||||
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// send the data to mutate and encode
|
||||
if (!write_all(fd_socket, buf, buf_size)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
if (wanted & SERVER_CROSSOVER_BIT) {
|
||||
|
||||
// since we requested crossover, we will first tell how much additional data
|
||||
// is to be expected
|
||||
put_uint32(ctrl_buf, (uint32_t)add_buf_size);
|
||||
if (!write_all(fd_socket, ctrl_buf, 4)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// send the additional data for crossover
|
||||
if (!write_all(fd_socket, add_buf, add_buf_size)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// lastly, a seed is required for crossover so send one
|
||||
put_uint64(ctrl_buf, (uint64_t)rand());
|
||||
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// since we requested mutation, we need to provide a seed for that
|
||||
put_uint64(ctrl_buf, (uint64_t)rand());
|
||||
if (!write_all(fd_socket, ctrl_buf, 8)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// obtain the required buffer size for the data that will be returned
|
||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
size_t new_size = (size_t)to_uint32(ctrl_buf);
|
||||
|
||||
// if the data is too large then we ignore this round
|
||||
if (new_size > max_size) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
if (new_size > buf_size) {
|
||||
|
||||
// buf is too small, need to use data->fuzz_buf, let's see whether we need
|
||||
// to reallocate
|
||||
if (new_size > data->fuzz_size) {
|
||||
|
||||
data->fuzz_size = new_size << 1;
|
||||
data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
|
||||
|
||||
}
|
||||
|
||||
*out_buf = data->fuzz_buf;
|
||||
|
||||
} else {
|
||||
|
||||
// new_size fits into buf, so re-use it
|
||||
*out_buf = buf;
|
||||
|
||||
}
|
||||
|
||||
// obtain the encoded data
|
||||
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
close(fd_socket);
|
||||
return new_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A post-processing function to use right before AFL writes the test case to
|
||||
* disk in order to execute the target.
|
||||
*
|
||||
* (Optional) If this functionality is not needed, simply don't define this
|
||||
* function.
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Buffer containing the test case to be executed
|
||||
* @param[in] buf_size Size of the test case
|
||||
* @param[out] out_buf Pointer to the buffer containing the test case after
|
||||
* processing. External library should allocate memory for out_buf.
|
||||
* The buf pointer may be reused (up to the given buf_size);
|
||||
* @return Size of the output buffer after processing or the needed amount.
|
||||
* A return of 0 indicates an error.
|
||||
*/
|
||||
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size, uint8_t **out_buf) {
|
||||
|
||||
struct sockaddr_un addr;
|
||||
int fd_socket;
|
||||
uint8_t ctrl_buf[8];
|
||||
|
||||
// initialize the socket
|
||||
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
|
||||
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// ask whether the server is alive
|
||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// see whether the server replies as expected
|
||||
if (!read_all(fd_socket, ctrl_buf, 1) ||
|
||||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||
|
||||
return fail_fatal(fd_socket, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// tell the server what we want and how much data will be sent
|
||||
ctrl_buf[0] = SERVER_DECODE_BIT;
|
||||
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
|
||||
if (!write_all(fd_socket, ctrl_buf, 5)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// send the data to decode
|
||||
if (!write_all(fd_socket, buf, buf_size)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
// obtain the required buffer size for the data that will be returned
|
||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
size_t new_size = (size_t)to_uint32(ctrl_buf);
|
||||
|
||||
// need to use data->post_process_buf, let's see whether we need to reallocate
|
||||
if (new_size > data->post_process_size) {
|
||||
|
||||
data->post_process_size = new_size << 1;
|
||||
data->post_process_buf =
|
||||
(uint8_t *)realloc(data->post_process_buf, data->post_process_size);
|
||||
|
||||
}
|
||||
|
||||
*out_buf = data->post_process_buf;
|
||||
|
||||
// obtain the decoded data
|
||||
if (!read_all(fd_socket, *out_buf, new_size)) {
|
||||
|
||||
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
|
||||
|
||||
}
|
||||
|
||||
close(fd_socket);
|
||||
return new_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
||||
|
||||
free(data->fuzz_buf);
|
||||
free(data->post_process_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||
#define BUF_VAR(type, name) \
|
||||
type * name##_buf; \
|
||||
size_t name##_size;
|
||||
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
|
||||
#define BUF_PARAMS(struct, name) \
|
||||
(void **)&struct->name##_buf, &struct->name##_size
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
@ -3,14 +3,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "custom_mutator_helpers.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include "mangle.h"
|
||||
|
||||
#define NUMBER_OF_MUTATIONS 5
|
||||
|
||||
uint8_t * queue_input;
|
||||
uint8_t *queue_input;
|
||||
size_t queue_input_size;
|
||||
afl_state_t * afl_struct;
|
||||
afl_state_t *afl_struct;
|
||||
run_t run;
|
||||
honggfuzz_t global;
|
||||
struct _dynfile_t dynfile;
|
||||
@ -18,8 +18,8 @@ struct _dynfile_t dynfile;
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
run_t * run;
|
||||
u8 * mutator_buf;
|
||||
run_t *run;
|
||||
u8 *mutator_buf;
|
||||
unsigned int seed;
|
||||
unsigned int extras_cnt, a_extras_cnt;
|
||||
|
||||
@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
/* When a new queue entry is added we check if there are new dictionary
|
||||
entries to add to honggfuzz structure */
|
||||
|
||||
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
void afl_custom_queue_new_entry(my_mutator_t *data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
if (run.global->mutate.dictionaryCnt >= 1024) return;
|
||||
|
||||
@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
../examples/custom_mutator_helpers.h
|
@ -1,6 +1,5 @@
|
||||
// This simple example just creates random buffer <= 100 filled with 'A'
|
||||
// needs -I /path/to/AFLplusplus/include
|
||||
//#include "custom_mutator_helpers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@ -8,19 +7,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "radamsa.h"
|
||||
#include "custom_mutator_helpers.h"
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_t *afl;
|
||||
|
||||
u8 *mutator_buf;
|
||||
|
||||
afl_state_t *afl;
|
||||
u8 *mutator_buf;
|
||||
unsigned int seed;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed);
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
|
@ -5,6 +5,8 @@ This uses the symcc to find new paths into the target.
|
||||
Note that this is a just a proof of concept example! It is better to use
|
||||
the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this.
|
||||
|
||||
Also the symqemu custom mutator is better than this.
|
||||
|
||||
To use this custom mutator follow the steps in the symcc repository
|
||||
[https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/)
|
||||
on how to build symcc and how to instrument a target binary (the same target
|
||||
|
14
custom_mutators/symqemu/Makefile
Normal file
14
custom_mutators/symqemu/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
||||
all: symqemu-mutator.so
|
||||
|
||||
CFLAGS += -O3 -funroll-loops
|
||||
|
||||
symqemu-mutator.so: symqemu.c
|
||||
$(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c
|
||||
|
||||
clean:
|
||||
rm -f symqemu-mutator.so *.o *~ core
|
19
custom_mutators/symqemu/README.md
Normal file
19
custom_mutators/symqemu/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# custum mutator: symqemu
|
||||
|
||||
This uses the symcc to find new paths into the target.
|
||||
|
||||
## How to build and use
|
||||
|
||||
To use this custom mutator follow the steps in the symqemu repository
|
||||
[https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/)
|
||||
on how to build symqemu-x86_x64 and put it in your `PATH`.
|
||||
|
||||
Just type `make` to build this custom mutator.
|
||||
|
||||
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...```
|
||||
|
||||
## Options
|
||||
|
||||
`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones.
|
||||
|
||||
`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes.
|
424
custom_mutators/symqemu/symqemu.c
Normal file
424
custom_mutators/symqemu/symqemu.c
Normal file
@ -0,0 +1,424 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include "common.h"
|
||||
|
||||
afl_state_t *afl_struct;
|
||||
static u32 debug = 0;
|
||||
static u32 found_items = 0;
|
||||
|
||||
#define SYMQEMU_LOCATION "symqemu"
|
||||
|
||||
#define DBG(x...) \
|
||||
if (debug) { fprintf(stderr, x); }
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
u32 all;
|
||||
u32 late;
|
||||
u8 *mutator_buf;
|
||||
u8 *out_dir;
|
||||
u8 *target;
|
||||
u8 *symqemu;
|
||||
u8 *input_file;
|
||||
u32 counter;
|
||||
u32 seed;
|
||||
u32 argc;
|
||||
u8 **argv;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
char *path = getenv("PATH");
|
||||
char *exec_name = "symqemu-x86_64";
|
||||
char *token = strtok(path, ":");
|
||||
char exec_path[4096];
|
||||
|
||||
while (token != NULL && data->symqemu == NULL) {
|
||||
|
||||
snprintf(exec_path, sizeof(exec_path), "%s/%s", token, exec_name);
|
||||
if (access(exec_path, X_OK) == 0) {
|
||||
|
||||
data->symqemu = (u8 *)strdup(exec_path);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
token = strtok(NULL, ":");
|
||||
|
||||
}
|
||||
|
||||
if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name);
|
||||
DBG("Found %s\n", data->symqemu);
|
||||
|
||||
if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) {
|
||||
|
||||
WARNF(
|
||||
"the symqemu module is not very effective with "
|
||||
"AFL_CUSTOM_MUTATOR_ONLY.");
|
||||
|
||||
}
|
||||
|
||||
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
|
||||
|
||||
free(data);
|
||||
perror("mutator_buf alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->target = getenv("AFL_CUSTOM_INFO_PROGRAM");
|
||||
|
||||
u8 *path_tmp = getenv("AFL_CUSTOM_INFO_OUT");
|
||||
u32 len = strlen(path_tmp) + 32;
|
||||
u8 *symqemu_path = malloc(len);
|
||||
data->out_dir = malloc(len);
|
||||
snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION);
|
||||
snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp);
|
||||
|
||||
(void)mkdir(symqemu_path, 0755);
|
||||
(void)mkdir(data->out_dir, 0755);
|
||||
|
||||
setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
|
||||
|
||||
data->input_file = getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT");
|
||||
|
||||
u8 *tmp = NULL;
|
||||
if ((tmp = getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) && *tmp) {
|
||||
|
||||
int argc = 0, index = 2;
|
||||
for (u32 i = 0; i < strlen(tmp); ++i)
|
||||
if (isspace(tmp[i])) ++argc;
|
||||
|
||||
data->argv = (u8 **)malloc((argc + 4) * sizeof(u8 **));
|
||||
u8 *p = strdup(tmp);
|
||||
|
||||
do {
|
||||
|
||||
data->argv[index] = p;
|
||||
while (*p && !isspace(*p))
|
||||
++p;
|
||||
if (*p) {
|
||||
|
||||
*p++ = 0;
|
||||
while (isspace(*p))
|
||||
++p;
|
||||
|
||||
}
|
||||
|
||||
if (strcmp(data->argv[index], "@@") == 0) {
|
||||
|
||||
if (!data->input_file) {
|
||||
|
||||
u32 ilen = strlen(symqemu_path) + 32;
|
||||
data->input_file = malloc(ilen);
|
||||
snprintf(data->input_file, ilen, "%s/.input", symqemu_path);
|
||||
|
||||
}
|
||||
|
||||
data->argv[index] = data->input_file;
|
||||
|
||||
}
|
||||
|
||||
DBG("%d: %s\n", index, data->argv[index]);
|
||||
index++;
|
||||
|
||||
} while (*p);
|
||||
|
||||
data->argv[index] = NULL;
|
||||
data->argc = index;
|
||||
|
||||
} else {
|
||||
|
||||
data->argv = (u8 **)malloc(8 * sizeof(u8 **));
|
||||
data->argc = 2;
|
||||
data->argv[2] = NULL;
|
||||
|
||||
}
|
||||
|
||||
data->argv[0] = data->symqemu;
|
||||
data->argv[1] = data->target;
|
||||
data->afl = afl;
|
||||
data->seed = seed;
|
||||
afl_struct = afl;
|
||||
|
||||
if (getenv("SYMQEMU_ALL")) { data->all = 1; }
|
||||
if (getenv("SYMQEMU_LATE")) { data->late = 1; }
|
||||
if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); }
|
||||
|
||||
DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir,
|
||||
data->target,
|
||||
data->input_file ? (char *)data->input_file : (char *)"<stdin>",
|
||||
data->argc);
|
||||
|
||||
if (debug) {
|
||||
|
||||
fprintf(stderr, "[");
|
||||
for (u32 i = 0; i <= data->argc; ++i)
|
||||
fprintf(stderr, " \"%s\"",
|
||||
data->argv[i] ? (char *)data->argv[i] : "<NULL>");
|
||||
fprintf(stderr, " ]\n");
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/* No need to receive a splicing item */
|
||||
void afl_custom_splice_optout(void *data) {
|
||||
|
||||
(void)(data);
|
||||
|
||||
}
|
||||
|
||||
/* Get unix time in milliseconds */
|
||||
|
||||
inline u64 get_cur_time(void) {
|
||||
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
gettimeofday(&tv, &tz);
|
||||
|
||||
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
|
||||
|
||||
}
|
||||
|
||||
u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) {
|
||||
|
||||
if (likely((!afl_struct->queue_cur->favored && !data->all) ||
|
||||
afl_struct->queue_cur->was_fuzzed)) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (likely(data->late)) {
|
||||
|
||||
if (unlikely(get_cur_time() - afl_struct->last_find_time <=
|
||||
10 * 60 * 1000)) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int pipefd[2];
|
||||
struct stat st;
|
||||
|
||||
if (afl_struct->afl_env.afl_no_ui) {
|
||||
|
||||
ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname);
|
||||
|
||||
}
|
||||
|
||||
if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) &&
|
||||
st.st_size)) {
|
||||
|
||||
PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname);
|
||||
|
||||
}
|
||||
|
||||
if (afl_struct->fsrv.use_stdin) {
|
||||
|
||||
if (pipe(pipefd) == -1) {
|
||||
|
||||
PFATAL(
|
||||
"Couldn't create a pipe for interacting with symqemu child process");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (data->input_file) {
|
||||
|
||||
int fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
ssize_t s = write(fd, buf, buf_size);
|
||||
close(fd);
|
||||
DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file);
|
||||
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
|
||||
if (pid == -1) return 0;
|
||||
|
||||
if (likely(pid)) {
|
||||
|
||||
if (!data->input_file || afl_struct->fsrv.use_stdin) {
|
||||
|
||||
close(pipefd[0]);
|
||||
|
||||
if (fcntl(pipefd[1], F_GETPIPE_SZ)) {
|
||||
|
||||
fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
|
||||
|
||||
}
|
||||
|
||||
ck_write(pipefd[1], buf, buf_size, data->input_file);
|
||||
|
||||
close(pipefd[1]);
|
||||
|
||||
}
|
||||
|
||||
pid = waitpid(pid, NULL, 0);
|
||||
DBG("symqemu finished executing!\n");
|
||||
|
||||
} else /* (pid == 0) */ { // child
|
||||
|
||||
if (afl_struct->fsrv.use_stdin) {
|
||||
|
||||
close(pipefd[1]);
|
||||
dup2(pipefd[0], 0);
|
||||
|
||||
}
|
||||
|
||||
DBG("exec=%s\n", data->target);
|
||||
if (!debug) {
|
||||
|
||||
close(1);
|
||||
close(2);
|
||||
dup2(afl_struct->fsrv.dev_null_fd, 1);
|
||||
dup2(afl_struct->fsrv.dev_null_fd, 2);
|
||||
|
||||
}
|
||||
|
||||
execvp((char *)data->argv[0], (char **)data->argv);
|
||||
fprintf(stderr, "Executing: [");
|
||||
for (u32 i = 0; i <= data->argc; ++i)
|
||||
fprintf(stderr, " \"%s\"",
|
||||
data->argv[i] ? (char *)data->argv[i] : "<NULL>");
|
||||
fprintf(stderr, " ]\n");
|
||||
FATAL("Failed to execute %s %s\n", data->argv[0], data->argv[1]);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
/* back in mother process */
|
||||
|
||||
struct dirent **nl;
|
||||
s32 i, items = scandir(data->out_dir, &nl, NULL, NULL);
|
||||
found_items = 0;
|
||||
char source_name[4096];
|
||||
|
||||
if (items > 0) {
|
||||
|
||||
for (i = 0; i < (u32)items; ++i) {
|
||||
|
||||
// symqemu output files start with a digit
|
||||
if (!isdigit(nl[i]->d_name[0])) continue;
|
||||
|
||||
struct stat st;
|
||||
snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
|
||||
nl[i]->d_name);
|
||||
DBG("file=%s\n", source_name);
|
||||
|
||||
if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
|
||||
|
||||
++found_items;
|
||||
|
||||
}
|
||||
|
||||
free(nl[i]);
|
||||
|
||||
}
|
||||
|
||||
free(nl);
|
||||
|
||||
}
|
||||
|
||||
DBG("Done, found %u items!\n", found_items);
|
||||
|
||||
return found_items;
|
||||
|
||||
}
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
|
||||
u8 **out_buf, u8 *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
struct dirent **nl;
|
||||
s32 done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL);
|
||||
char source_name[4096];
|
||||
|
||||
if (items > 0) {
|
||||
|
||||
for (i = 0; i < (u32)items; ++i) {
|
||||
|
||||
// symqemu output files start with a digit
|
||||
if (!isdigit(nl[i]->d_name[0])) continue;
|
||||
|
||||
struct stat st;
|
||||
snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
|
||||
nl[i]->d_name);
|
||||
DBG("file=%s\n", source_name);
|
||||
|
||||
if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
|
||||
|
||||
int fd = open(source_name, O_RDONLY);
|
||||
if (fd < 0) { goto got_an_issue; }
|
||||
|
||||
ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
|
||||
close(fd);
|
||||
|
||||
DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r);
|
||||
|
||||
if (r < 1) { goto got_an_issue; }
|
||||
|
||||
done = 1;
|
||||
--found_items;
|
||||
unlink(source_name);
|
||||
|
||||
*out_buf = data->mutator_buf;
|
||||
return (u32)r;
|
||||
|
||||
}
|
||||
|
||||
free(nl[i]);
|
||||
|
||||
}
|
||||
|
||||
free(nl);
|
||||
|
||||
}
|
||||
|
||||
got_an_issue:
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->mutator_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,61 @@
|
||||
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.08a (dev)
|
||||
- afl-fuzz:
|
||||
- new mutation engine: mutations that favor discovery more paths are
|
||||
prefered until no new finds for 10 minutes then switching to mutations
|
||||
that favor triggering crashes. Modes and switch time can be configured
|
||||
with `-P`. Also input mode for the target can be defined with `-a` to
|
||||
be `text` or `binary` (defaults to `generic`)
|
||||
- new custom mutator that has the new afl++ engine (so it can easily
|
||||
incorporated into new custom mutators), and also comes with a standalone
|
||||
command line tool! See custom_mutators/aflpp/standalone/
|
||||
- display the state of the fuzzing run in the UI :-)
|
||||
- fix timeout setting if '+' is used or a session is restarted
|
||||
- afl-cmin/afl-cmin.bash:
|
||||
- fixed a bug inherited from vanilla AFL where a coverage of
|
||||
map[123] = 11 would be the same as map[1123] = 1
|
||||
- warn on crashing inputs
|
||||
- afl-cc:
|
||||
- fixed an off-by-one instrumentation of iselect, hurting coverage a bit.
|
||||
Thanks to @amykweon for spotting and fixing!
|
||||
- @toka fixed a bug in laf-intel signed integer comparison splitting,
|
||||
thanks a lot!!
|
||||
- more LLVM compatability
|
||||
- frida_mode:
|
||||
- support for long form instrumentation on x86_x64 and arm64
|
||||
|
||||
|
||||
### Version ++4.07c (release)
|
||||
- afl-fuzz:
|
||||
- reverse reading the seeds only on restarts (increases performance)
|
||||
- new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
|
||||
data before post process on finds (for atnwalk custom mutator)
|
||||
- new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from
|
||||
loaded libs after forkserver initialization (required by Mozilla)
|
||||
- afl-cc:
|
||||
- added @responsefile support
|
||||
- new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
|
||||
(https://github.com/fgsect/WAFL) project
|
||||
- error and print help if afl-clan-lto is used with lto=thin
|
||||
- rewrote our PCGUARD pass to be compatible with LLVM 15+ shenanigans,
|
||||
requires LLVM 13+ now instead of 10.0.1+
|
||||
- fallback to native LLVM PCGUARD if our PCGUARD is unavailable
|
||||
- fixed a crash in GCC CMPLOG
|
||||
- afl-showmap:
|
||||
- added custom mutator post_process and send support
|
||||
- add `-I filelist` option, an alternative to `-i in_dir`
|
||||
- afl-cmin + afl-cmin.bash:
|
||||
- `-T threads` parallel task support, can be a huge speedup!
|
||||
- qemu_mode:
|
||||
- Persistent mode + QASAN support for ppc32 targets by @worksbutnottested
|
||||
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
|
||||
- two new custom mutators are now available:
|
||||
- TritonDSE in custom_mutators/aflpp_tritondse
|
||||
- SymQEMU in custom_mutators/symqemu
|
||||
|
||||
|
||||
### Version ++4.06c (release)
|
||||
- afl-fuzz:
|
||||
- ensure temporary file descriptor is closed when not used
|
||||
@ -211,7 +266,7 @@
|
||||
afl-showmap and other tools.
|
||||
- afl-cc:
|
||||
- detect overflow reads on initial input buffer for asan
|
||||
- new cmplog mode (incompatible with older afl++ versions)
|
||||
- new cmplog mode (incompatible with older AFL++ versions)
|
||||
- support llvm IR select instrumentation for default PCGUARD and LTO
|
||||
- fix for shared linking on MacOS
|
||||
- better selective instrumentation AFL_LLVM_{ALLOW|DENY}LIST
|
||||
|
62
docs/FAQ.md
62
docs/FAQ.md
@ -171,6 +171,14 @@ If you find an interesting or important question missing, submit it via
|
||||
The more "unstable" edges there are, the harder it is for AFL++ to identify
|
||||
valid new paths.
|
||||
|
||||
If you fuzz in persistent mode (`AFL_LOOP` or `LLVMFuzzerTestOneInput()`
|
||||
harnesses, a large number of unstable edges can mean that the target keeps
|
||||
internal state and therefore it is possible that crashes cannot be replayed.
|
||||
In such a case do either **not** fuzz in persistent mode (remove `AFL_LOOP()`
|
||||
from your harness or call `LLVMFuzzerTestOneInput()` harnesses with `@@`),
|
||||
or set a low `AFL_LOOP` value, e.g. 100, and enable `AFL_PERSISTENT_RECORD`
|
||||
in `config.h` with the same value.
|
||||
|
||||
A value above 90% is usually fine and a value above 80% is also still ok, and
|
||||
even a value above 20% can still result in successful finds of bugs. However,
|
||||
it is recommended that for values below 90% or 80% you should take
|
||||
@ -229,7 +237,8 @@ If you find an interesting or important question missing, submit it via
|
||||
If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then
|
||||
the existing map will be used also for the newly loaded libraries, which
|
||||
allows it to work, however, the efficiency of the fuzzing will be partially
|
||||
degraded.
|
||||
degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
|
||||
additionally tell AFL++ to ignore any coverage from the late loaded libaries.
|
||||
</p></details>
|
||||
|
||||
<details>
|
||||
@ -270,3 +279,54 @@ If you find an interesting or important question missing, submit it via
|
||||
|
||||
Solution: just do an `export AFL_MAP_SIZE=(the value in the warning)`.
|
||||
</p></details>
|
||||
|
||||
<details>
|
||||
<summary id="linker-errors">Linker errors.</summary><p>
|
||||
|
||||
If you compile C++ harnesses and see `undefined reference` errors for
|
||||
variables named `__afl_...`, e.g.:
|
||||
|
||||
```
|
||||
/usr/bin/ld: /tmp/test-d3085f.o: in function `foo::test()':
|
||||
test.cpp:(.text._ZN3fooL4testEv[_ZN3fooL4testEv]+0x35): undefined reference to `foo::__afl_connected'
|
||||
clang: error: linker command failed with exit code 1 (use -v to see invocation)
|
||||
```
|
||||
|
||||
Then you use AFL++ macros like `__AFL_LOOP` within a namespace and this
|
||||
will not work.
|
||||
|
||||
Solution: Move that harness portion to the global namespace, e.g. before:
|
||||
```
|
||||
#include <cstdio>
|
||||
namespace foo {
|
||||
static void test() {
|
||||
while(__AFL_LOOP(1000)) {
|
||||
foo::function();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
foo::test();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
after:
|
||||
```
|
||||
#include <cstdio>
|
||||
static void mytest() {
|
||||
while(__AFL_LOOP(1000)) {
|
||||
foo::function();
|
||||
}
|
||||
}
|
||||
namespace foo {
|
||||
static void test() {
|
||||
mytest();
|
||||
}
|
||||
}
|
||||
int main(int argc, char** argv) {
|
||||
foo::test();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
</p></details>
|
||||
|
@ -3,9 +3,8 @@
|
||||
## Linux on x86
|
||||
|
||||
An easy way to install AFL++ with everything compiled is available via docker:
|
||||
You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-12 -
|
||||
hence afl-clang-lto is available) or just pull directly from the Docker Hub
|
||||
(for x86_64 and arm64):
|
||||
You can use the [Dockerfile](../Dockerfile) or just pull directly from the
|
||||
Docker Hub (for x86_64 and arm64):
|
||||
|
||||
```shell
|
||||
docker pull aflplusplus/aflplusplus:
|
||||
@ -21,14 +20,14 @@ development state of AFL++.
|
||||
If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-12` with
|
||||
whatever llvm version is available. We recommend llvm 12, 13 or 14.
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
|
||||
whatever llvm version is available. We recommend llvm 13, 14, 15 or 16.
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
|
||||
# try to install llvm 12 and install the distro default if that fails
|
||||
sudo apt-get install -y lld-12 llvm-12 llvm-12-dev clang-12 || sudo apt-get install -y lld llvm llvm-dev clang
|
||||
# try to install llvm 14 and install the distro default if that fails
|
||||
sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || sudo apt-get install -y lld llvm llvm-dev clang
|
||||
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
|
||||
sudo apt-get install -y ninja-build # for QEMU mode
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
@ -51,7 +50,7 @@ make source-only
|
||||
|
||||
These build targets exist:
|
||||
|
||||
* all: the main afl++ binaries and llvm/gcc instrumentation
|
||||
* all: the main AFL++ binaries and llvm/gcc instrumentation
|
||||
* binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode,
|
||||
qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator,
|
||||
libtokencap
|
||||
@ -79,22 +78,20 @@ make STATIC=1
|
||||
These build options exist:
|
||||
|
||||
* STATIC - compile AFL++ static
|
||||
* CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)
|
||||
* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
|
||||
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for
|
||||
debug purposes
|
||||
* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
|
||||
* DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
* LLVM_DEBUG - shows llvm deprecation warnings
|
||||
* PROFILING - compile afl-fuzz with profiling information
|
||||
* INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
|
||||
normal fuzzing
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
* NO_NYX - disable building nyx mode dependencies
|
||||
* NO_CORESIGHT - disable building coresight (arm64 only)
|
||||
* NO_UNICORN_ARM64 - disable building unicorn on arm64
|
||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
|
||||
(e.g., Debian)
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)
|
||||
|
||||
e.g.: `make LLVM_CONFIG=llvm-config-14`
|
||||
|
||||
|
@ -131,6 +131,11 @@ jitter, or is a hash map function etc., then it should not be instrumented.
|
||||
To be able to exclude these functions (based on AFL++'s measured stability), the
|
||||
following process will allow to identify functions with variable edges.
|
||||
|
||||
Note that this is only useful for non-persistent targets!
|
||||
If a persistent target is unstable whereas when run non-persistent is fine,
|
||||
then this means that the target is keeping internal state, which is bad for
|
||||
fuzzing. Fuzz such targets **without** persistent mode.
|
||||
|
||||
Four steps are required to do this and it also requires quite some knowledge of
|
||||
coding and/or disassembly and is effectively possible only with `afl-clang-fast`
|
||||
`PCGUARD` and `afl-clang-lto` `LTO` instrumentation.
|
||||
|
@ -145,12 +145,15 @@ def deinit(): # optional for Python
|
||||
|
||||
- `fuzz` (optional):
|
||||
|
||||
This method performs custom mutations on a given input. It also accepts an
|
||||
additional test case. Note that this function is optional - but it makes
|
||||
sense to use it. You would only skip this if `post_process` is used to fix
|
||||
checksums etc. so if you are using it, e.g., as a post processing library.
|
||||
Note that a length > 0 *must* be returned!
|
||||
The returned output buffer is under **your** memory management!
|
||||
This method performs your custom mutations on a given input.
|
||||
The add_buf is the contents of another queue item that can be used for
|
||||
splicing - or anything else - and can also be ignored. If you are not
|
||||
using this additional data then define `splice_optout` (see above).
|
||||
This function is optional.
|
||||
Returing a length of 0 is valid and is interpreted as skipping this
|
||||
one mutation result.
|
||||
For non-Python: the returned output buffer is under **your** memory
|
||||
management!
|
||||
|
||||
- `describe` (optional):
|
||||
|
||||
@ -304,6 +307,34 @@ Note: for some distributions, you might also need the package `python[3]-apt`.
|
||||
In case your setup is different, set the necessary variables like this:
|
||||
`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
|
||||
|
||||
### Helpers
|
||||
|
||||
For C/C++ custom mutators you get a pointer to `afl_state_t *afl` in the
|
||||
`afl_custom_init()` which contains all information that you need.
|
||||
Note that if you access it, you need to recompile your custom mutator if
|
||||
you update AFL++ because the structure might have changed!
|
||||
|
||||
For mutators written in Python, Rust, GO, etc. there are a few environment
|
||||
variables set to help you to get started:
|
||||
|
||||
`AFL_CUSTOM_INFO_PROGRAM` - the program name of the target that is executed.
|
||||
If your custom mutator is used with modes like Qemu (`-Q`), this will still
|
||||
contain the target program, not afl-qemu-trace.
|
||||
|
||||
`AFL_CUSTOM_INFO_PROGRAM_INPUT` - if the `-f` parameter is used with afl-fuzz
|
||||
then this value is found in this environment variable.
|
||||
|
||||
`AFL_CUSTOM_INFO_PROGRAM_ARGV` - this contains the parameters given to the
|
||||
target program and still has the `@@` identifier in there.
|
||||
|
||||
Note: If `AFL_CUSTOM_INFO_PROGRAM_INPUT` is empty and `AFL_CUSTOM_INFO_PROGRAM_ARGV`
|
||||
is either empty or does not contain `@@` then the target gets the input via
|
||||
`stdin`.
|
||||
|
||||
`AFL_CUSTOM_INFO_OUT` - This is the output directory for this fuzzer instance,
|
||||
so if `afl-fuzz` was called with `-o out -S foobar`, then this will be set to
|
||||
`out/foobar`.
|
||||
|
||||
### Custom Mutator Preparation
|
||||
|
||||
For C/C++ mutators, the source code must be compiled as a shared object:
|
||||
|
@ -156,7 +156,7 @@ Available options:
|
||||
- LTO - LTO instrumentation
|
||||
- NATIVE - clang's original pcguard based instrumentation
|
||||
- NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
|
||||
- PCGUARD - our own pcgard based instrumentation (default)
|
||||
- PCGUARD - our own pcguard based instrumentation (default)
|
||||
|
||||
#### CMPLOG
|
||||
|
||||
@ -240,7 +240,9 @@ combined.
|
||||
the default `0x10000`. A value of 0 or empty sets the map address to be
|
||||
dynamic (the original AFL way, which is slower).
|
||||
- `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic.
|
||||
|
||||
- `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars
|
||||
(e.g. the highest location ID) are not injected. Needed to instrument with
|
||||
[WAFL](https://github.com/fgsect/WAFL.git).
|
||||
For more information, see
|
||||
[instrumentation/README.lto.md](../instrumentation/README.lto.md).
|
||||
|
||||
@ -404,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
|
||||
- If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session
|
||||
(not at startup), it will terminate. If you do not want this, then you can
|
||||
set `AFL_IGNORE_PROBLEMS`.
|
||||
set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage
|
||||
from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`.
|
||||
|
||||
- When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
|
||||
fuzzer to import test cases from other instances before doing anything else.
|
||||
@ -616,6 +619,14 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
- Setting `AFL_INST_LIBS` causes the translator to also instrument the code
|
||||
inside any dynamically linked libraries (notably including glibc).
|
||||
|
||||
- You can use `AFL_QEMU_INST_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to just
|
||||
instrument specific memory locations, e.g. a specific library.
|
||||
Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
|
||||
|
||||
- You can use `AFL_QEMU_EXCLUDE_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to **NOT**
|
||||
instrument specific memory locations, e.g. a specific library.
|
||||
Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
|
||||
|
||||
- It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some
|
||||
of the basic blocks, which can be useful when dealing with very complex
|
||||
binaries.
|
||||
@ -677,6 +688,8 @@ support.
|
||||
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
|
||||
code. Code is considered to be JIT if the executable segment is not backed by
|
||||
a file.
|
||||
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
|
||||
runtime. Strictly limits instrumentation to what has been included.
|
||||
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
||||
instrumentation (the default where available). Required to use
|
||||
`AFL_FRIDA_INST_TRACE`.
|
||||
|
@ -8,6 +8,7 @@ Here are some good write-ups to show how to effectively use AFL++:
|
||||
|
||||
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
|
||||
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
|
||||
* [https://bushido-sec.com/index.php/2023/06/19/the-art-of-fuzzing/](https://bushido-sec.com/index.php/2023/06/19/the-art-of-fuzzing/)
|
||||
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
|
||||
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
|
||||
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
|
||||
@ -20,6 +21,14 @@ training, then we can highly recommend the following:
|
||||
|
||||
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
|
||||
|
||||
Here is a good forkflow description (and tutorial) for qemu_mode:
|
||||
|
||||
* [https://airbus-seclab.github.io/AFLplusplus-blogpost/](https://airbus-seclab.github.io/AFLplusplus-blogpost/)
|
||||
|
||||
Here is good workflow description for frida_mode:
|
||||
|
||||
* [https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html](https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html)
|
||||
|
||||
If you are interested in fuzzing structured data (where you define what the
|
||||
structure is), these links have you covered (some are outdated though):
|
||||
|
||||
|
@ -7,6 +7,8 @@ variables.
|
||||
|
||||
In FRIDA mode, binary programs are instrumented, similarly to QEMU mode.
|
||||
|
||||
A tutorial can be found at [https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html](https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html)
|
||||
|
||||
## Current progress
|
||||
|
||||
As FRIDA mode is new, it is missing a lot of features. The design is such that
|
||||
@ -178,11 +180,13 @@ Default is 256Mb.
|
||||
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
|
||||
code. Code is considered to be JIT if the executable segment is not backed by
|
||||
a file.
|
||||
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
|
||||
runtime. Strictly limits instrumentation to what has been included.
|
||||
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
||||
instrumentation (the default where available). Required to use
|
||||
`AFL_FRIDA_INST_TRACE`.
|
||||
* `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start
|
||||
of each block.
|
||||
`AFL_FRIDA_INST_TRACE`.
|
||||
* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
|
||||
instrumented address block translations.
|
||||
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
|
||||
|
@ -844,6 +844,12 @@ class Afl {
|
||||
static setInstrumentLibraries() {
|
||||
Afl.jsApiSetInstrumentLibraries();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
|
||||
*/
|
||||
static setInstrumentNoDynamicLoad() {
|
||||
Afl.jsApiSetInstrumentNoDynamicLoad();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@
|
||||
js_api_set_instrument_jit;
|
||||
js_api_set_instrument_libraries;
|
||||
js_api_set_instrument_instructions;
|
||||
js_api_set_instrument_no_dynamic_load;
|
||||
js_api_set_instrument_no_optimize;
|
||||
js_api_set_instrument_regs_file;
|
||||
js_api_set_instrument_seed;
|
||||
|
@ -14,8 +14,6 @@ void entry_init(void);
|
||||
|
||||
void entry_start(void);
|
||||
|
||||
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
|
||||
|
||||
void entry_on_fork(void);
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
extern gboolean ranges_debug_maps;
|
||||
extern gboolean ranges_inst_libs;
|
||||
extern gboolean ranges_inst_jit;
|
||||
extern gboolean ranges_inst_dynamic_load;
|
||||
|
||||
void ranges_config(void);
|
||||
void ranges_init(void);
|
||||
|
@ -78,6 +78,7 @@ void entry_init(void) {
|
||||
|
||||
void entry_start(void) {
|
||||
|
||||
FVERBOSE("AFL_ENTRYPOINT reached");
|
||||
if (persistent_start == 0) {
|
||||
|
||||
ranges_exclude();
|
||||
@ -85,32 +86,7 @@ void entry_start(void) {
|
||||
|
||||
}
|
||||
|
||||
if (entry_point == 0) { entry_launch(); }
|
||||
|
||||
}
|
||||
|
||||
static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
|
||||
|
||||
UNUSED_PARAMETER(cpu_context);
|
||||
UNUSED_PARAMETER(user_data);
|
||||
entry_compiled = TRUE;
|
||||
entry_launch();
|
||||
|
||||
}
|
||||
|
||||
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
|
||||
|
||||
UNUSED_PARAMETER(output);
|
||||
FVERBOSE("AFL_ENTRYPOINT reached");
|
||||
|
||||
if (persistent_start == 0) {
|
||||
|
||||
ranges_exclude();
|
||||
stalker_trust();
|
||||
|
||||
}
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
|
||||
if (unlikely(begin)) { instrument_debug_start(instr->address, output); }
|
||||
|
||||
if (instr->address == entry_point) { entry_prologue(iterator, output); }
|
||||
if (instr->address == persistent_start) { persistent_prologue(output); }
|
||||
if (instr->address == persistent_ret) { persistent_epilogue(output); }
|
||||
|
||||
|
@ -76,6 +76,45 @@ typedef struct {
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint32_t b_imm8; /* br #XX (end) */
|
||||
|
||||
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
|
||||
|
||||
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
uint32_t ldr_x0_p_prev_loc_1; /* ldr x0, #0xXXXX */
|
||||
uint32_t ldr_x1_ptr_x0; /* ldr x1, [x0] */
|
||||
|
||||
uint32_t ldr_x0_p_area_offset; /* ldr x0, #0xXXXX */
|
||||
uint32_t eor_x0_x1_x0; /* eor x0, x1, x0 */
|
||||
uint32_t ldr_x1_p_area_ptr; /* ldr x1, #0xXXXX */
|
||||
uint32_t add_x0_x1_x0; /* add x0, x1, x0 */
|
||||
|
||||
uint32_t ldrb_w1_x0; /* ldrb w1, [x0] */
|
||||
uint32_t add_w1_w1_1; /* add w1, w1, #1 */
|
||||
uint32_t add_w1_w1_w1_lsr_8; /* add x1, x1, x1, lsr #8 */
|
||||
|
||||
uint32_t strb_w1_ptr_x0; /* strb w1, [x0] */
|
||||
|
||||
uint32_t ldr_x0_p_prev_loc_2; /* ldr x0, #0xXXXX */
|
||||
uint32_t ldr_x1_p_area_offset_ror; /* ldr x1, #0xXXXX */
|
||||
uint32_t str_x1_ptr_x0; /* str x1, [x0] */
|
||||
|
||||
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
uint32_t b_end; /* skip the data */
|
||||
|
||||
uint64_t area_ptr;
|
||||
uint64_t prev_loc_ptr;
|
||||
uint64_t area_offset;
|
||||
uint64_t area_offset_ror;
|
||||
|
||||
uint8_t end[0];
|
||||
|
||||
} afl_log_code_asm_long_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef union {
|
||||
@ -85,6 +124,13 @@ typedef union {
|
||||
|
||||
} afl_log_code;
|
||||
|
||||
typedef union {
|
||||
|
||||
afl_log_code_asm_long_t code;
|
||||
uint8_t bytes[0];
|
||||
|
||||
} afl_log_code_long;
|
||||
|
||||
static const afl_log_code_asm_t template =
|
||||
{
|
||||
|
||||
@ -119,6 +165,46 @@ static const afl_log_code_asm_t template =
|
||||
|
||||
;
|
||||
|
||||
static const afl_log_code_asm_long_t template_long =
|
||||
{.b_imm8 = 0x1400001a,
|
||||
|
||||
.restoration_prolog = 0xa8c947f0, /* ldp x16, x17, [sp], #0x90 */
|
||||
|
||||
.stp_x0_x1 = 0xa93607e0, /* stp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
.ldr_x0_p_prev_loc_1 = 0x58000220, /* ldr x0, #0xXXXX */
|
||||
.ldr_x1_ptr_x0 = 0xf9400001, /* ldr x1, [x0] */
|
||||
|
||||
.ldr_x0_p_area_offset = 0x58000220, /* ldr x0, #0xXXXX */
|
||||
.eor_x0_x1_x0 = 0xca000020, /* eor x0, x1, x0 */
|
||||
.ldr_x1_p_area_ptr = 0x58000161, /* ldr x1, #0xXXXX */
|
||||
.add_x0_x1_x0 = 0x8b000020, /* add x0, x1, x0 */
|
||||
|
||||
.ldrb_w1_x0 = 0x39400001, /* ldrb w1, [x0] */
|
||||
.add_w1_w1_1 = 0x11000421, /* add w1, w1, #1 */
|
||||
.add_w1_w1_w1_lsr_8 = 0x8b412021, /* add x1, x1, x1, lsr #8 */
|
||||
|
||||
.strb_w1_ptr_x0 = 0x39000001, /* strb w1, [x0] */
|
||||
|
||||
.ldr_x0_p_prev_loc_2 = 0x580000e0, /* ldr x0, #0xXXXX */
|
||||
.ldr_x1_p_area_offset_ror = 0x58000141, /* ldr x1, #0xXXXX */
|
||||
.str_x1_ptr_x0 = 0xf9000001, /* str x1, [x0] */
|
||||
|
||||
.ldp_x0_x1 = 0xa97607e0, /* ldp x0, x1, [sp, #-0xa0] */
|
||||
|
||||
.b_end = 0x14000009, /* skip the data */
|
||||
|
||||
.area_ptr = 0x0,
|
||||
.prev_loc_ptr = 0x0,
|
||||
.area_offset = 0x0,
|
||||
.area_offset_ror = 0x0,
|
||||
|
||||
.end = {}
|
||||
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
|
||||
return true;
|
||||
@ -266,16 +352,22 @@ static gboolean instrument_coverage_in_range(gssize offset) {
|
||||
|
||||
}
|
||||
|
||||
static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
|
||||
static bool instrument_patch_ardp(guint32 *patch, GumAddress insn,
|
||||
GumAddress target) {
|
||||
|
||||
if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); }
|
||||
if (!PAGE_ALIGNED(target)) {
|
||||
|
||||
FWARNF("Target not page aligned");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK);
|
||||
if (!instrument_coverage_in_range(distance)) {
|
||||
|
||||
FATAL("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
|
||||
distance);
|
||||
FVERBOSE("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
|
||||
distance);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@ -283,6 +375,95 @@ static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
|
||||
guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
|
||||
*patch |= imm_low;
|
||||
*patch |= imm_high;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool instrument_write_inline(GumArm64Writer *cw, GumAddress code_addr,
|
||||
guint64 area_offset, gsize area_offset_ror) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
code.code = template;
|
||||
|
||||
/*
|
||||
* Given our map is allocated on a 64KB boundary and our map is a multiple of
|
||||
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
|
||||
* by our previous_pc, so this too should be 64KB aligned.
|
||||
*/
|
||||
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
|
||||
g_assert(PAGE_ALIGNED(__afl_area_ptr));
|
||||
|
||||
if (!instrument_patch_ardp(
|
||||
&code.code.adrp_x0_prev_loc1,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
|
||||
GUM_ADDRESS(instrument_previous_pc_addr))) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
code.code.mov_x0_curr_loc |= area_offset << 5;
|
||||
|
||||
if (!instrument_patch_ardp(
|
||||
&code.code.adrp_x1_area_ptr,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
|
||||
GUM_ADDRESS(__afl_area_ptr))) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (!instrument_patch_ardp(
|
||||
&code.code.adrp_x0_prev_loc2,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
|
||||
GUM_ADDRESS(instrument_previous_pc_addr))) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
|
||||
|
||||
if (instrument_suppress) {
|
||||
|
||||
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
|
||||
|
||||
} else {
|
||||
|
||||
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
|
||||
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
|
||||
sizeof(afl_log_code) - offset);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool instrument_write_inline_long(GumArm64Writer *cw, GumAddress code_addr,
|
||||
guint64 area_offset, gsize area_offset_ror) {
|
||||
|
||||
afl_log_code_long code = {0};
|
||||
code.code = template_long;
|
||||
|
||||
code.code.area_ptr = GUM_ADDRESS(__afl_area_ptr);
|
||||
code.code.prev_loc_ptr = GUM_ADDRESS(instrument_previous_pc_addr);
|
||||
code.code.area_offset = area_offset;
|
||||
code.code.area_offset_ror = GUM_ADDRESS(area_offset_ror);
|
||||
|
||||
if (instrument_suppress) {
|
||||
|
||||
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
|
||||
|
||||
} else {
|
||||
|
||||
size_t offset = offsetof(afl_log_code_long, code.stp_x0_x1);
|
||||
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
|
||||
sizeof(afl_log_code_long) - offset);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@ -312,6 +493,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
|
||||
}
|
||||
|
||||
// gum_arm64_writer_put_brk_imm(cw, 0x0);
|
||||
// uint32_t jmp_dot = 0x14000000;
|
||||
// gum_arm64_writer_put_bytes(cw, (guint8 *)&jmp_dot, sizeof(jmp_dot));
|
||||
|
||||
if (instrument_suppress) { instrument_coverage_suppress_init(); }
|
||||
|
||||
@ -343,47 +526,19 @@ void instrument_coverage_optimize(const cs_insn *instr,
|
||||
|
||||
}
|
||||
|
||||
code.code = template;
|
||||
|
||||
/*
|
||||
* Given our map is allocated on a 64KB boundary and our map is a multiple of
|
||||
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
|
||||
* by our previous_pc, so this too should be 64KB aligned.
|
||||
*/
|
||||
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
|
||||
g_assert(PAGE_ALIGNED(__afl_area_ptr));
|
||||
|
||||
instrument_patch_ardp(
|
||||
&code.code.adrp_x0_prev_loc1,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
|
||||
GUM_ADDRESS(instrument_previous_pc_addr));
|
||||
|
||||
code.code.mov_x0_curr_loc |= area_offset << 5;
|
||||
|
||||
instrument_patch_ardp(
|
||||
&code.code.adrp_x1_area_ptr,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
|
||||
GUM_ADDRESS(__afl_area_ptr));
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
|
||||
|
||||
instrument_patch_ardp(
|
||||
&code.code.adrp_x0_prev_loc2,
|
||||
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
|
||||
GUM_ADDRESS(instrument_previous_pc_addr));
|
||||
code.code = template;
|
||||
|
||||
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
|
||||
if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
|
||||
|
||||
if (instrument_suppress) {
|
||||
if (!instrument_write_inline_long(cw, code_addr, area_offset,
|
||||
area_offset_ror)) {
|
||||
|
||||
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
|
||||
FATAL("Failed to write inline instrumentation");
|
||||
|
||||
} else {
|
||||
|
||||
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
|
||||
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
|
||||
sizeof(afl_log_code) - offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ typedef union {
|
||||
} jcc_insn;
|
||||
|
||||
static GHashTable *coverage_blocks = NULL;
|
||||
static GHashTable *coverage_blocks_long = NULL;
|
||||
|
||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||
|
||||
@ -127,6 +128,64 @@ typedef struct {
|
||||
|
||||
} afl_log_code_asm_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
// cur_location = (block_address >> 4) ^ (block_address << 8);
|
||||
// shared_mem[cur_location ^ prev_location]++;
|
||||
// prev_location = cur_location >> 1;
|
||||
|
||||
// mov QWORD PTR [rsp-0x88],rax
|
||||
// lahf
|
||||
// mov QWORD PTR [rsp-0x90],rax
|
||||
// mov QWORD PTR [rsp-0x98],rbx
|
||||
|
||||
// mov rax, 0xXXXXXXXXXXXXXXXXX /* p_prev_loc */
|
||||
// mov eax, dword ptr [rax] /* prev_loc */
|
||||
// xor eax,0x3f77 /* cur_loc */
|
||||
|
||||
// mov rbx, 0xXXXXXXXXXXXXXXXXX /* map */
|
||||
// add rax,rbx
|
||||
|
||||
// mov bl,BYTE PTR [rax]
|
||||
// add bl,0x1
|
||||
// adc bl,0x0
|
||||
// mov BYTE PTR [rax],bl
|
||||
|
||||
// mov rax, 0xXXXXXXXXXXXXXXXXX /* p_prev_loc */
|
||||
// mov dword ptr [rax], 0xXXXXXXXXX /* prev_loc */
|
||||
|
||||
// mov rbx,QWORD PTR [rsp-0x98]
|
||||
// mov rax,QWORD PTR [rsp-0x90]
|
||||
// sahf
|
||||
// mov rax,QWORD PTR [rsp-0x88]
|
||||
|
||||
uint8_t mov_rax_rsp_88[8];
|
||||
uint8_t lahf;
|
||||
uint8_t mov_rax_rsp_90[8];
|
||||
uint8_t mov_rbx_rsp_98[8];
|
||||
|
||||
uint8_t mov_rax_prev_loc_ptr1[10];
|
||||
uint8_t mov_eax_prev_loc[2];
|
||||
uint8_t xor_eax_curr_loc[5];
|
||||
|
||||
uint8_t mov_rbx_map_ptr[10];
|
||||
uint8_t add_rax_rbx[3];
|
||||
|
||||
uint8_t mov_rbx_ptr_rax[2];
|
||||
uint8_t add_bl_1[3];
|
||||
uint8_t adc_bl_0[3];
|
||||
uint8_t mov_ptr_rax_rbx[2];
|
||||
|
||||
uint8_t mov_rax_prev_loc_ptr2[10];
|
||||
uint8_t mov_prev_loc_curr_loc_shr1[6];
|
||||
|
||||
uint8_t mov_rsp_98_rbx[8];
|
||||
uint8_t mov_rsp_90_rax[8];
|
||||
uint8_t sahf;
|
||||
uint8_t mov_rsp_88_rax[8];
|
||||
|
||||
} afl_log_code_asm_long_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static const afl_log_code_asm_t template =
|
||||
@ -158,6 +217,41 @@ static const afl_log_code_asm_t template =
|
||||
|
||||
;
|
||||
|
||||
static const afl_log_code_asm_long_t template_long =
|
||||
{
|
||||
|
||||
.mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
|
||||
.lahf = 0x9f,
|
||||
.mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
|
||||
.mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
.mov_rax_prev_loc_ptr1 = {0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF},
|
||||
.mov_eax_prev_loc = {0x8b, 0x00},
|
||||
.xor_eax_curr_loc = {0x35},
|
||||
|
||||
.mov_rbx_map_ptr = {0x48, 0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF},
|
||||
.add_rax_rbx = {0x48, 0x01, 0xd8},
|
||||
|
||||
.mov_rbx_ptr_rax = {0x8a, 0x18},
|
||||
.add_bl_1 = {0x80, 0xc3, 0x01},
|
||||
.adc_bl_0 = {0x80, 0xd3, 0x00},
|
||||
.mov_ptr_rax_rbx = {0x88, 0x18},
|
||||
|
||||
.mov_rax_prev_loc_ptr2 = {0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF},
|
||||
.mov_prev_loc_curr_loc_shr1 = {0xc7, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
.mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF},
|
||||
.mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF},
|
||||
.sahf = 0x9e,
|
||||
.mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF},
|
||||
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
typedef union {
|
||||
|
||||
afl_log_code_asm_t code;
|
||||
@ -165,6 +259,13 @@ typedef union {
|
||||
|
||||
} afl_log_code;
|
||||
|
||||
typedef union {
|
||||
|
||||
afl_log_code_asm_long_t code;
|
||||
uint8_t bytes[0];
|
||||
|
||||
} afl_log_code_long;
|
||||
|
||||
void instrument_coverage_optimize_init(void) {
|
||||
|
||||
FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
|
||||
@ -182,16 +283,19 @@ static void instrument_coverage_switch_insn(GumStalkerObserver *self,
|
||||
|
||||
cs_x86 *x86;
|
||||
cs_x86_op *op;
|
||||
bool is_short = false;
|
||||
bool is_long = false;
|
||||
|
||||
if (from_insn == NULL) { return; }
|
||||
|
||||
x86 = &from_insn->detail->x86;
|
||||
op = x86->operands;
|
||||
|
||||
if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) {
|
||||
is_short = g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target));
|
||||
is_long =
|
||||
g_hash_table_contains(coverage_blocks_long, GSIZE_TO_POINTER(*target));
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
if (!is_short && !is_long) { return; }
|
||||
|
||||
switch (from_insn->id) {
|
||||
|
||||
@ -212,15 +316,41 @@ static void instrument_coverage_switch_insn(GumStalkerObserver *self,
|
||||
|
||||
break;
|
||||
case X86_INS_RET:
|
||||
instrument_cache_insert(start_address,
|
||||
(guint8 *)*target + sizeof(afl_log_code));
|
||||
if (is_short) {
|
||||
|
||||
instrument_cache_insert(start_address,
|
||||
(guint8 *)*target + sizeof(afl_log_code));
|
||||
|
||||
} else if (is_long) {
|
||||
|
||||
instrument_cache_insert(start_address,
|
||||
(guint8 *)*target + sizeof(afl_log_code_long));
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("Something has gone wrong here!");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
*target = (guint8 *)*target + sizeof(afl_log_code);
|
||||
if (is_short) {
|
||||
|
||||
*target = (guint8 *)*target + sizeof(afl_log_code);
|
||||
|
||||
} else if (is_long) {
|
||||
|
||||
*target = (guint8 *)*target + sizeof(afl_log_code_long);
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("Something has gone wrong here!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -270,22 +400,22 @@ static void instrument_coverage_suppress_init(void) {
|
||||
|
||||
}
|
||||
|
||||
coverage_blocks_long = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (coverage_blocks_long == NULL) {
|
||||
|
||||
FATAL("Failed to g_hash_table_new, errno: %d", errno);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_write(GumAddress address,
|
||||
GumStalkerOutput *output) {
|
||||
bool instrument_write_inline(GumX86Writer *cw, GumAddress code_addr,
|
||||
guint32 area_offset, guint32 area_offset_ror) {
|
||||
|
||||
afl_log_code code = {0};
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
guint64 area_offset = instrument_get_offset_hash(address);
|
||||
gsize map_size_pow2;
|
||||
gsize area_offset_ror;
|
||||
GumAddress code_addr = cw->pc;
|
||||
afl_log_code code = {0};
|
||||
|
||||
code.code = template;
|
||||
|
||||
/* mov_prev_loc_curr_loc_shr1 */
|
||||
|
||||
gssize prev_loc_value =
|
||||
GPOINTER_TO_SIZE(instrument_previous_pc_addr) -
|
||||
(code_addr + offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
|
||||
@ -294,11 +424,7 @@ static void instrument_coverage_write(GumAddress address,
|
||||
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
|
||||
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(gint) -
|
||||
sizeof(guint32);
|
||||
if (!instrument_coverage_in_range(prev_loc_value)) {
|
||||
|
||||
FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value);
|
||||
|
||||
}
|
||||
if (!instrument_coverage_in_range(prev_loc_value)) { return false; }
|
||||
|
||||
*((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
|
||||
|
||||
@ -311,11 +437,7 @@ static void instrument_coverage_write(GumAddress address,
|
||||
gssize prev_loc_value_offset2 =
|
||||
offsetof(afl_log_code, code.mov_eax_prev_loc) +
|
||||
sizeof(code.code.mov_eax_prev_loc) - sizeof(gint);
|
||||
if (!instrument_coverage_in_range(prev_loc_value)) {
|
||||
|
||||
FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value2);
|
||||
|
||||
}
|
||||
if (!instrument_coverage_in_range(prev_loc_value)) { return false; }
|
||||
|
||||
*((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2;
|
||||
|
||||
@ -338,12 +460,7 @@ static void instrument_coverage_write(GumAddress address,
|
||||
(code_addr + offsetof(afl_log_code, code.lea_rbx_area_ptr) +
|
||||
sizeof(code.code.lea_rbx_area_ptr)));
|
||||
|
||||
if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) {
|
||||
|
||||
FATAL("Patch out of range (lea_rbx_area_ptr_value): 0x%016lX",
|
||||
lea_rbx_area_ptr_value);
|
||||
|
||||
}
|
||||
if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) { return false; }
|
||||
|
||||
*((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value;
|
||||
|
||||
@ -353,12 +470,100 @@ static void instrument_coverage_write(GumAddress address,
|
||||
offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) +
|
||||
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
|
||||
|
||||
*((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror);
|
||||
|
||||
if (instrument_suppress) {
|
||||
|
||||
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool instrument_write_inline_long(GumX86Writer *cw, guint32 area_offset,
|
||||
guint32 area_offset_ror) {
|
||||
|
||||
afl_log_code_long code = {0};
|
||||
code.code = template_long;
|
||||
|
||||
/* mov_rax_prev_loc_ptr1 */
|
||||
gssize mov_rax_prev_loc_ptr1_offset =
|
||||
offsetof(afl_log_code_long, code.mov_rax_prev_loc_ptr1) +
|
||||
sizeof(code.code.mov_rax_prev_loc_ptr1) - sizeof(gsize);
|
||||
*((gsize *)&code.bytes[mov_rax_prev_loc_ptr1_offset]) =
|
||||
GPOINTER_TO_SIZE(instrument_previous_pc_addr);
|
||||
|
||||
/* xor_eax_curr_loc */
|
||||
gssize xor_eax_curr_loc_offset =
|
||||
offsetof(afl_log_code_long, code.xor_eax_curr_loc) +
|
||||
sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32);
|
||||
*((guint32 *)&code.bytes[xor_eax_curr_loc_offset]) = area_offset;
|
||||
|
||||
/* mov_rbx_map_ptr */
|
||||
gsize mov_rbx_map_ptr_offset =
|
||||
offsetof(afl_log_code_long, code.mov_rbx_map_ptr) +
|
||||
sizeof(code.code.mov_rbx_map_ptr) - sizeof(gsize);
|
||||
*((gsize *)&code.bytes[mov_rbx_map_ptr_offset]) =
|
||||
GPOINTER_TO_SIZE(__afl_area_ptr);
|
||||
|
||||
/* mov_rax_prev_loc_ptr2 */
|
||||
gssize mov_rax_prev_loc_ptr2_offset =
|
||||
offsetof(afl_log_code_long, code.mov_rax_prev_loc_ptr2) +
|
||||
sizeof(code.code.mov_rax_prev_loc_ptr2) - sizeof(gsize);
|
||||
*((gsize *)&code.bytes[mov_rax_prev_loc_ptr2_offset]) =
|
||||
GPOINTER_TO_SIZE(instrument_previous_pc_addr);
|
||||
|
||||
/* mov_prev_loc_curr_loc_shr1 */
|
||||
gssize mov_prev_loc_curr_loc_shr1_offset =
|
||||
offsetof(afl_log_code_long, code.mov_prev_loc_curr_loc_shr1) +
|
||||
sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32);
|
||||
*((guint32 *)&code.bytes[mov_prev_loc_curr_loc_shr1_offset]) =
|
||||
(guint32)(area_offset_ror);
|
||||
|
||||
if (instrument_suppress) {
|
||||
|
||||
if (!g_hash_table_add(coverage_blocks_long, GSIZE_TO_POINTER(cw->code))) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void instrument_coverage_write(GumAddress address,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
guint64 area_offset = (guint32)instrument_get_offset_hash(address);
|
||||
gsize map_size_pow2;
|
||||
guint32 area_offset_ror;
|
||||
GumAddress code_addr = cw->pc;
|
||||
|
||||
map_size_pow2 = util_log2(__afl_map_size);
|
||||
area_offset_ror = (guint32)util_rotate(instrument_get_offset_hash(address), 1,
|
||||
map_size_pow2);
|
||||
|
||||
if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
|
||||
|
||||
if (!instrument_write_inline_long(cw, area_offset, area_offset_ror)) {
|
||||
|
||||
FATAL("Failed to write inline instrumentation");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -380,17 +585,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
|
||||
|
||||
}
|
||||
|
||||
if (instrument_suppress) {
|
||||
|
||||
instrument_coverage_suppress_init();
|
||||
|
||||
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
|
||||
|
||||
FATAL("Failed - g_hash_table_add");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (instrument_suppress) { instrument_coverage_suppress_init(); }
|
||||
|
||||
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
|
||||
|
||||
|
@ -150,6 +150,12 @@ class Afl {
|
||||
static setInstrumentLibraries() {
|
||||
Afl.jsApiSetInstrumentLibraries();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
|
||||
*/
|
||||
static setInstrumentNoDynamicLoad() {
|
||||
Afl.jsApiSetInstrumentNoDynamicLoad();
|
||||
}
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
|
||||
*/
|
||||
@ -342,6 +348,7 @@ Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_de
|
||||
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
|
||||
Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
|
||||
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
|
||||
Afl.jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction("js_api_set_instrument_no_dynamic_load", "void", []);
|
||||
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
|
||||
Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]);
|
||||
Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);
|
||||
|
@ -156,6 +156,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions(
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void
|
||||
js_api_set_instrument_no_dynamic_load(void) {
|
||||
|
||||
ranges_inst_dynamic_load = FALSE;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
|
||||
void) {
|
||||
|
||||
|
@ -17,8 +17,8 @@ static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
|
||||
|
@ -197,7 +197,7 @@ static void afl_print_env(void) {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
void afl_frida_config(void) {
|
||||
|
||||
FOKF(cRED "**********************");
|
||||
FOKF(cRED "* " cYEL "******************" cRED " *");
|
||||
@ -225,9 +225,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
|
||||
js_start();
|
||||
|
||||
/* Initialize */
|
||||
output_init();
|
||||
|
||||
embedded_init();
|
||||
entry_init();
|
||||
instrument_init();
|
||||
@ -240,12 +238,35 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
ranges_init();
|
||||
stats_init();
|
||||
|
||||
/* Start */
|
||||
}
|
||||
|
||||
void afl_frida_run(void) {
|
||||
|
||||
stalker_start();
|
||||
entry_start();
|
||||
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void afl_frida_start(void) {
|
||||
|
||||
afl_frida_config();
|
||||
afl_frida_run();
|
||||
|
||||
}
|
||||
|
||||
typedef void *(*entry_func_t)(size_t a1, size_t a2, size_t a3, size_t a4,
|
||||
size_t a5, size_t a6);
|
||||
|
||||
static void *on_entry(size_t a1, size_t a2, size_t a3, size_t a4, size_t a5,
|
||||
size_t a6) {
|
||||
|
||||
intercept_unhook(GSIZE_TO_POINTER(entry_point));
|
||||
afl_frida_run();
|
||||
entry_func_t entry = (entry_func_t)entry_point;
|
||||
return entry(a1, a2, a3, a4, a5, a6);
|
||||
|
||||
}
|
||||
|
||||
static int on_main(int argc, char **argv, char **envp) {
|
||||
|
||||
int ret;
|
||||
@ -254,7 +275,17 @@ static int on_main(int argc, char **argv, char **envp) {
|
||||
|
||||
intercept_unhook_self();
|
||||
|
||||
afl_frida_start();
|
||||
afl_frida_config();
|
||||
|
||||
if (entry_point == 0) {
|
||||
|
||||
afl_frida_run();
|
||||
|
||||
} else {
|
||||
|
||||
intercept_hook(GSIZE_TO_POINTER(entry_point), on_entry, NULL);
|
||||
|
||||
}
|
||||
|
||||
if (js_main_hook != NULL) {
|
||||
|
||||
|
@ -18,6 +18,7 @@ typedef struct {
|
||||
gboolean ranges_debug_maps = FALSE;
|
||||
gboolean ranges_inst_libs = FALSE;
|
||||
gboolean ranges_inst_jit = FALSE;
|
||||
gboolean ranges_inst_dynamic_load = TRUE;
|
||||
|
||||
static GArray *module_ranges = NULL;
|
||||
static GArray *libs_ranges = NULL;
|
||||
@ -25,6 +26,7 @@ static GArray *jit_ranges = NULL;
|
||||
static GArray *include_ranges = NULL;
|
||||
static GArray *exclude_ranges = NULL;
|
||||
static GArray *ranges = NULL;
|
||||
static GArray *whole_memory_ranges = NULL;
|
||||
|
||||
static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
@ -387,6 +389,21 @@ static GArray *collect_jit_ranges(void) {
|
||||
|
||||
}
|
||||
|
||||
static GArray *collect_whole_mem_ranges(void) {
|
||||
|
||||
GArray *result;
|
||||
GumMemoryRange range;
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
range.base_address = 0;
|
||||
range.size = G_MAXULONG;
|
||||
|
||||
g_array_append_val(result, range);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra,
|
||||
GumMemoryRange *rb) {
|
||||
|
||||
@ -574,11 +591,17 @@ void ranges_config(void) {
|
||||
if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; }
|
||||
if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; }
|
||||
if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; }
|
||||
if (getenv("AFL_FRIDA_INST_NO_DYNAMIC_LOAD") != NULL) {
|
||||
|
||||
ranges_inst_dynamic_load = FALSE;
|
||||
|
||||
}
|
||||
|
||||
if (ranges_debug_maps) { ranges_print_debug_maps(); }
|
||||
|
||||
include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
|
||||
exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");
|
||||
whole_memory_ranges = collect_whole_mem_ranges();
|
||||
|
||||
}
|
||||
|
||||
@ -628,10 +651,20 @@ void ranges_init(void) {
|
||||
print_ranges("step4", step4);
|
||||
|
||||
/*
|
||||
* After step4, we have the total ranges to be instrumented, we now subtract
|
||||
* that from the original ranges of the modules to configure stalker.
|
||||
* After step 4 we have the total ranges to be instrumented, we now subtract
|
||||
* that either from the original ranges of the modules or from the whole
|
||||
* memory if AFL_INST_NO_DYNAMIC_LOAD to configure the stalker.
|
||||
*/
|
||||
step5 = subtract_ranges(module_ranges, step4);
|
||||
if (ranges_inst_dynamic_load) {
|
||||
|
||||
step5 = subtract_ranges(module_ranges, step4);
|
||||
|
||||
} else {
|
||||
|
||||
step5 = subtract_ranges(whole_memory_ranges, step4);
|
||||
|
||||
}
|
||||
|
||||
print_ranges("step5", step5);
|
||||
|
||||
ranges = merge_ranges(step5);
|
||||
|
@ -67,3 +67,8 @@ debug:
|
||||
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||
--ex 'set disassembly-flavor intel' \
|
||||
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
|
||||
lldb:
|
||||
lldb \
|
||||
-O 'settings set target.env-vars DYLD_INSERT_LIBRARIES=$(ROOT)afl-frida-trace.so' \
|
||||
-- $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
|
@ -178,6 +178,13 @@ class Afl {
|
||||
Afl.jsApiSetInstrumentLibraries();
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
|
||||
*/
|
||||
public static setInstrumentNoDynamicLoad(): void {
|
||||
Afl.jsApiSetInstrumentNoDynamicLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
|
||||
*/
|
||||
@ -443,6 +450,11 @@ class Afl {
|
||||
"void",
|
||||
[]);
|
||||
|
||||
private static readonly jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction(
|
||||
"js_api_set_instrument_no_dynamic_load",
|
||||
"void",
|
||||
[]);
|
||||
|
||||
private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction(
|
||||
"js_api_set_instrument_no_optimize",
|
||||
"void",
|
||||
|
@ -184,6 +184,7 @@ struct queue_entry {
|
||||
handicap, /* Number of queue cycles behind */
|
||||
depth, /* Path depth */
|
||||
exec_cksum, /* Checksum of the execution trace */
|
||||
custom, /* Marker for custom mutators */
|
||||
stats_mutated; /* stats: # of mutations performed */
|
||||
|
||||
u8 *trace_mini; /* Trace bytes, if kept */
|
||||
@ -399,7 +400,8 @@ typedef struct afl_env_vars {
|
||||
afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
|
||||
afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
|
||||
afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts,
|
||||
afl_no_startup_calibration, afl_no_warn_instability;
|
||||
afl_no_startup_calibration, afl_no_warn_instability,
|
||||
afl_post_process_keep_original;
|
||||
|
||||
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
|
||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
|
||||
@ -492,7 +494,8 @@ typedef struct afl_state {
|
||||
*orig_cmdline, /* Original command line */
|
||||
*infoexec; /* Command to execute on a new crash */
|
||||
|
||||
u32 hang_tmout; /* Timeout used for hang det (ms) */
|
||||
u32 hang_tmout, /* Timeout used for hang det (ms) */
|
||||
stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */
|
||||
no_unlink, /* do not unlink cur_input */
|
||||
@ -501,14 +504,12 @@ typedef struct afl_state {
|
||||
custom_splice_optout, /* Custom mutator no splice buffer */
|
||||
is_main_node, /* if this is the main node */
|
||||
is_secondary_node, /* if this is a secondary instance */
|
||||
pizza_is_served; /* pizza mode */
|
||||
|
||||
u32 stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
u8 schedule; /* Power schedule (default: EXPLORE)*/
|
||||
u8 havoc_max_mult;
|
||||
|
||||
u8 skip_deterministic, /* Skip deterministic stages? */
|
||||
pizza_is_served, /* pizza mode */
|
||||
input_mode, /* target wants text inputs */
|
||||
fuzz_mode, /* coverage/exploration or crash/exploitation mode */
|
||||
schedule, /* Power schedule (default: EXPLORE)*/
|
||||
havoc_max_mult, /* havoc multiplier */
|
||||
skip_deterministic, /* Skip deterministic stages? */
|
||||
use_splicing, /* Recombine input files? */
|
||||
non_instrumented_mode, /* Run in non-instrumented mode? */
|
||||
score_changed, /* Scoring for favorites changed? */
|
||||
@ -595,7 +596,8 @@ typedef struct afl_state {
|
||||
last_hang_time, /* Time for most recent hang (ms) */
|
||||
longest_find_time, /* Longest time taken for a find */
|
||||
exit_on_time, /* Delay to exit if no new paths */
|
||||
sync_time; /* Sync time (ms) */
|
||||
sync_time, /* Sync time (ms) */
|
||||
switch_fuzz_mode; /* auto or fixed fuzz mode */
|
||||
|
||||
u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
|
||||
subseq_tmouts; /* Number of timeouts in a row */
|
||||
@ -1103,7 +1105,6 @@ u32 count_bits(afl_state_t *, u8 *);
|
||||
u32 count_bytes(afl_state_t *, u8 *);
|
||||
u32 count_non_255_bytes(afl_state_t *, u8 *);
|
||||
void simplify_trace(afl_state_t *, u8 *);
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#ifdef WORD_SIZE_64
|
||||
void discover_word(u8 *ret, u64 *current, u64 *virgin);
|
||||
#else
|
||||
@ -1117,6 +1118,9 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
#ifndef AFL_SHOWMAP
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#endif
|
||||
|
||||
/* Extras */
|
||||
|
||||
@ -1192,11 +1196,14 @@ void fix_up_sync(afl_state_t *);
|
||||
void check_asan_opts(afl_state_t *);
|
||||
void check_binary(afl_state_t *, u8 *);
|
||||
void check_if_tty(afl_state_t *);
|
||||
void setup_signal_handlers(void);
|
||||
void save_cmdline(afl_state_t *, u32, char **);
|
||||
void read_foreign_testcases(afl_state_t *, int);
|
||||
void write_crash_readme(afl_state_t *afl);
|
||||
u8 check_if_text_buf(u8 *buf, u32 len);
|
||||
#ifndef AFL_SHOWMAP
|
||||
void setup_signal_handlers(void);
|
||||
#endif
|
||||
char *get_fuzzing_state(afl_state_t *afl);
|
||||
|
||||
/* CmpLog */
|
||||
|
||||
@ -1218,7 +1225,7 @@ double rand_next_percent(afl_state_t *afl);
|
||||
|
||||
static inline u32 rand_below(afl_state_t *afl, u32 limit) {
|
||||
|
||||
if (limit <= 1) return 0;
|
||||
if (unlikely(limit <= 1)) return 0;
|
||||
|
||||
/* The boundary not being necessarily a power of 2,
|
||||
we need to ensure the result uniformity. */
|
||||
@ -1251,7 +1258,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
|
||||
expand havoc mode */
|
||||
static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) {
|
||||
|
||||
if (limit <= 1) return 0;
|
||||
if (unlikely(limit <= 1)) return 0;
|
||||
|
||||
switch (rand_below(afl, 3)) {
|
||||
|
||||
|
2662
include/afl-mutations.h
Normal file
2662
include/afl-mutations.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,7 @@
|
||||
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
|
||||
|
||||
#ifndef _WANT_ORIGINAL_AFL_ALLOC
|
||||
// afl++ stuff without memory corruption checks - for speed
|
||||
// AFL++ stuff without memory corruption checks - for speed
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
@ -322,7 +322,7 @@ static inline void DFL_ck_free(void *mem) {
|
||||
static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
void *ret;
|
||||
u32 old_size = 0;
|
||||
u32 old_size = 0;
|
||||
|
||||
if (!size) {
|
||||
|
||||
@ -392,7 +392,7 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
void *ret;
|
||||
u32 size;
|
||||
u32 size;
|
||||
|
||||
if (!str) return NULL;
|
||||
|
||||
@ -438,14 +438,14 @@ struct TRK_obj {
|
||||
|
||||
void *ptr;
|
||||
char *file, *func;
|
||||
u32 line;
|
||||
u32 line;
|
||||
|
||||
};
|
||||
|
||||
#ifdef AFL_MAIN
|
||||
|
||||
struct TRK_obj *TRK[ALLOC_BUCKETS];
|
||||
u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
#define alloc_report() TRK_report()
|
||||
|
||||
@ -704,12 +704,11 @@ static inline void *afl_realloc(void **buf, size_t size_needed) {
|
||||
*buf = NULL;
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = newer_buf;
|
||||
|
||||
}
|
||||
|
||||
new_buf = newer_buf;
|
||||
memset(((u8 *)new_buf) + current_size, 0, next_size - current_size);
|
||||
|
||||
new_buf->complete_size = next_size;
|
||||
*buf = (void *)(new_buf->buf);
|
||||
return *buf;
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#define CMP_MAP_W 65536
|
||||
#define CMP_MAP_H 32
|
||||
#define CMP_MAP_RTN_H (CMP_MAP_H / 4)
|
||||
#define CMP_MAP_RTN_H (CMP_MAP_H / 2)
|
||||
|
||||
#define SHAPE_BYTES(x) (x + 1)
|
||||
|
||||
|
@ -115,6 +115,11 @@ u8 *stringify_mem_size(u8 *buf, size_t len, u64 val);
|
||||
|
||||
u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Unsafe describe time delta as simple string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *u_simplestring_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Unsafe Describe integer. The buf sizes are not checked.
|
||||
This is unsafe but fast.
|
||||
Will return buf for convenience. */
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.06c"
|
||||
#define VERSION "++4.08a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -43,6 +43,12 @@
|
||||
Default: 8MB (defined in bytes) */
|
||||
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
|
||||
|
||||
/* Default time until when no more coverage finds are happening afl-fuzz
|
||||
switches to exploitation mode. It automatically switches back when new
|
||||
coverage is found.
|
||||
Default: 300 (seconds) */
|
||||
#define STRATEGY_SWITCH_TIME 1000
|
||||
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
@ -81,7 +87,7 @@
|
||||
will be kept and written to the crash/ directory as RECORD:... files.
|
||||
Note that every crash will be written, not only unique ones! */
|
||||
|
||||
//#define AFL_PERSISTENT_RECORD
|
||||
// #define AFL_PERSISTENT_RECORD
|
||||
|
||||
/* console output colors: There are three ways to configure its behavior
|
||||
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
||||
|
@ -37,6 +37,10 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CRASH_EXITCODE",
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"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",
|
||||
@ -65,6 +69,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FRIDA_INST_INSN",
|
||||
"AFL_FRIDA_INST_JIT",
|
||||
"AFL_FRIDA_INST_NO_CACHE",
|
||||
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
|
||||
"AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
||||
@ -105,6 +110,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_HARDEN",
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
||||
"AFL_IGNORE_PROBLEMS",
|
||||
"AFL_IGNORE_PROBLEMS_COVERAGE",
|
||||
"AFL_IGNORE_TIMEOUTS",
|
||||
"AFL_IGNORE_UNKNOWN_ENVS",
|
||||
"AFL_IMPORT_FIRST",
|
||||
@ -159,8 +165,9 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_LLVM_SKIP_NEVERZERO",
|
||||
"AFL_NO_AFFINITY",
|
||||
"AFL_TRY_AFFINITY",
|
||||
"AFL_LLVM_LTO_STARTID",
|
||||
"AFL_LLVM_LTO_DONTWRITEID",
|
||||
"AFL_LLVM_LTO_SKIPINIT"
|
||||
"AFL_LLVM_LTO_STARTID",
|
||||
"AFL_NO_ARITH",
|
||||
"AFL_NO_AUTODICT",
|
||||
"AFL_NO_BUILTIN",
|
||||
@ -186,6 +193,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_PATH",
|
||||
"AFL_PERFORMANCE_FILE",
|
||||
"AFL_PERSISTENT_RECORD",
|
||||
"AFL_POST_PROCESS_KEEP_ORIGINAL",
|
||||
"AFL_PRELOAD",
|
||||
"AFL_TARGET_ENV",
|
||||
"AFL_PYTHON_MODULE",
|
||||
|
@ -151,6 +151,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
bool uses_asan; /* Target uses ASAN? */
|
||||
|
||||
bool keep_coverage; /* use coverage feature */
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
||||
@ -160,6 +162,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
|
||||
u8 *coverage_map; /* for coverage feature */
|
||||
|
||||
char *cmplog_binary; /* the name of the cmplog binary */
|
||||
|
||||
/* persistent mode replay functionality */
|
||||
|
@ -7,7 +7,7 @@ For the GCC-based instrumentation, see
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
! llvm_mode works with llvm versions 3.8 up to 13 !
|
||||
! llvm_mode works with llvm versions 3.8 up to 17 - but 13+ is recommended !
|
||||
|
||||
The code in this directory allows you to instrument programs for AFL++ using
|
||||
true compiler-level instrumentation, instead of the more crude assembly-level
|
||||
@ -280,3 +280,27 @@ Please note that the default counter implementations are not thread safe!
|
||||
|
||||
Support for thread safe counters in mode LLVM CLASSIC can be activated with
|
||||
setting `AFL_LLVM_THREADSAFE_INST=1`.
|
||||
|
||||
## 8) Source code coverage through instrumentation
|
||||
|
||||
Measuring source code coverage is a common task in fuzzing, but it is very
|
||||
difficut to do in some situations (e.g. when using snapshot fuzzing).
|
||||
|
||||
When using the `AFL_LLVM_INSTRUMENT=llvm-codecov` option, afl-cc will use
|
||||
native trace-pc-guard instrumentation but additionally select options that
|
||||
are required to utilize the instrumentation for source code coverage.
|
||||
|
||||
In particular, it will switch the instrumentation to be per basic block
|
||||
instead of instrumenting edges, disable all guard pruning and enable the
|
||||
experimental pc-table support that allows the runtime to gather 100% of
|
||||
instrumented basic blocks at start, including their locations.
|
||||
|
||||
Note: You must compile AFL with the `CODE_COVERAGE=1` option to enable the
|
||||
respective parts in the AFL compiler runtime. Support is currently only
|
||||
implemented for Nyx, but can in theory also work without Nyx.
|
||||
|
||||
Note: You might have to adjust `MAP_SIZE_POW2` in include/config.h to ensure
|
||||
that your coverage map is large enough to hold all basic blocks of your
|
||||
target program without any collisions.
|
||||
|
||||
More documentation on how to utilize this with Nyx will follow.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SanitizeCoverage.cpp ported to afl++ LTO :-) */
|
||||
/* SanitizeCoverage.cpp ported to AFL++ LTO :-) */
|
||||
|
||||
#define AFL_LLVM_PASS
|
||||
|
||||
@ -19,8 +19,10 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#else
|
||||
#include "llvm/IR/EHPersonalities.h"
|
||||
#endif
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/Analysis/PostDominators.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
@ -49,7 +51,9 @@
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Instrumentation.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
@ -234,7 +238,7 @@ class ModuleSanitizerCoverageLTO
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
// const SpecialCaseList * Allowlist;
|
||||
// const SpecialCaseList * Blocklist;
|
||||
uint32_t autodictionary = 1;
|
||||
@ -260,7 +264,7 @@ class ModuleSanitizerCoverageLTO
|
||||
Value *MapPtrFixed = NULL;
|
||||
std::ofstream dFile;
|
||||
size_t found = 0;
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
};
|
||||
|
||||
@ -404,7 +408,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||
Int8Ty = IRB.getInt8Ty();
|
||||
Int1Ty = IRB.getInt1Ty();
|
||||
|
||||
/* afl++ START */
|
||||
/* AFL++ START */
|
||||
char *ptr;
|
||||
LLVMContext &Ctx = M.getContext();
|
||||
Ct = &Ctx;
|
||||
@ -978,7 +982,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||
|
||||
}
|
||||
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
SanCovTracePCIndir =
|
||||
M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
|
||||
@ -1002,10 +1006,11 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||
for (auto &F : M)
|
||||
instrumentFunction(F, DTCallback, PDTCallback);
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
if (dFile.is_open()) dFile.close();
|
||||
|
||||
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
|
||||
if (!getenv("AFL_LLVM_LTO_SKIPINIT") &&
|
||||
(!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr)) {
|
||||
|
||||
// yes we could create our own function, insert it into ctors ...
|
||||
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
|
||||
@ -1155,7 +1160,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||
|
||||
}
|
||||
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
// We don't reference these arrays directly in any of our runtime functions,
|
||||
// so we need to prevent them from being dead stripped.
|
||||
@ -1212,10 +1217,10 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
|
||||
// (catchswitch blocks).
|
||||
if (BB->getFirstInsertionPt() == BB->end()) return false;
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
|
||||
return false;
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
|
||||
|
||||
@ -1257,10 +1262,10 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
|
||||
// if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
|
||||
// return;
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
if (!F.size()) return;
|
||||
if (!isInInstrumentList(&F, FMNAME)) return;
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
|
||||
SplitAllCriticalEdges(
|
||||
@ -1473,8 +1478,8 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection(
|
||||
|
||||
ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
|
||||
auto Array = new GlobalVariable(
|
||||
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
|
||||
Constant::getNullValue(ArrayTy), "__sancov_gen_");
|
||||
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
|
||||
Constant::getNullValue(ArrayTy), "__sancov_gen_");
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
if (TargetTriple.supportsCOMDAT() &&
|
||||
@ -1558,7 +1563,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
|
||||
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
if (BlockList.size()) {
|
||||
|
||||
int skip = 0;
|
||||
@ -1580,7 +1585,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
|
||||
@ -1646,7 +1651,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
|
||||
|
||||
if (Options.TracePCGuard) {
|
||||
|
||||
// afl++ START
|
||||
// AFL++ START
|
||||
++afl_global_id;
|
||||
|
||||
if (dFile.is_open()) {
|
||||
@ -1710,7 +1715,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
|
||||
// done :)
|
||||
|
||||
inst++;
|
||||
// afl++ END
|
||||
// AFL++ END
|
||||
|
||||
/*
|
||||
XXXXXXXXXXXXXXXXXXX
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,14 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
@ -105,6 +113,50 @@ u32 __afl_dictionary_len;
|
||||
u64 __afl_map_addr;
|
||||
u32 __afl_first_final_loc;
|
||||
|
||||
typedef struct afl_module_info_t afl_module_info_t;
|
||||
|
||||
struct afl_module_info_t {
|
||||
|
||||
// A unique id starting with 0
|
||||
u32 id;
|
||||
|
||||
// Name and base address of the module
|
||||
char *name;
|
||||
uintptr_t base_address;
|
||||
|
||||
// PC Guard start/stop
|
||||
u32 start;
|
||||
u32 stop;
|
||||
|
||||
// PC Table begin/end
|
||||
const uintptr_t *pcs_beg;
|
||||
const uintptr_t *pcs_end;
|
||||
|
||||
u8 mapped;
|
||||
|
||||
afl_module_info_t *next;
|
||||
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
uintptr_t PC, PCFlags;
|
||||
|
||||
} PCTableEntry;
|
||||
|
||||
afl_module_info_t *__afl_module_info = NULL;
|
||||
|
||||
u32 __afl_pcmap_size = 0, __afl_pcmap_shmem = 1;
|
||||
uintptr_t *__afl_pcmap_ptr = NULL;
|
||||
|
||||
// Maximum path length on Linux
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
// Maximum length of an uint32_t as string
|
||||
#define START_STOP_MAX 10
|
||||
|
||||
/* 1 if we are running in afl, and the forkserver was started, else 0 */
|
||||
u32 __afl_connected = 0;
|
||||
|
||||
@ -496,11 +548,12 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_map_size && __afl_map_size > MAP_SIZE) {
|
||||
|
||||
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
|
||||
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
|
||||
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
|
||||
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
_exit(1);
|
||||
fprintf(stderr, "FS_ERROR_MAP_SIZE\n");
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
@ -512,13 +565,13 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
|
||||
|
||||
if (__afl_map_addr)
|
||||
if (__afl_map_addr)
|
||||
send_forkserver_error(FS_ERROR_MAP_ADDR);
|
||||
else
|
||||
send_forkserver_error(FS_ERROR_SHMAT);
|
||||
|
||||
perror("shmat for map");
|
||||
_exit(1);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
@ -678,6 +731,32 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
char *pcmap_id_str = getenv("__AFL_PCMAP_SHM_ID");
|
||||
|
||||
if (pcmap_id_str) {
|
||||
|
||||
__afl_pcmap_size = __afl_map_size * sizeof(void *);
|
||||
u32 shm_id = atoi(pcmap_id_str);
|
||||
|
||||
__afl_pcmap_ptr = (uintptr_t *)shmat(shm_id, NULL, 0);
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: Received %p via shmat for pcmap\n",
|
||||
__afl_pcmap_ptr);
|
||||
|
||||
}
|
||||
|
||||
} else if (getenv("__AFL_CODE_COVERAGE") ||
|
||||
|
||||
getenv("AFL_DUMP_CODE_COVERAGE")) {
|
||||
|
||||
__afl_pcmap_size = __afl_map_size * sizeof(void *);
|
||||
__afl_pcmap_ptr = (uintptr_t *)malloc(__afl_pcmap_size);
|
||||
__afl_pcmap_shmem = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* unmap SHM. */
|
||||
@ -686,6 +765,15 @@ static void __afl_unmap_shm(void) {
|
||||
|
||||
if (!__afl_already_initialized_shm) return;
|
||||
|
||||
if (__afl_pcmap_size) {
|
||||
|
||||
if (__afl_pcmap_shmem) { shmdt((void *)__afl_pcmap_ptr); }
|
||||
__afl_pcmap_ptr = NULL;
|
||||
__afl_pcmap_size = 0;
|
||||
__afl_pcmap_shmem = 1;
|
||||
|
||||
}
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
|
||||
if (id_str) {
|
||||
@ -1001,9 +1089,88 @@ static void __afl_start_snapshots(void) {
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
if (__afl_already_initialized_forkserver) return;
|
||||
if (__afl_already_initialized_forkserver) { return; }
|
||||
__afl_already_initialized_forkserver = 1;
|
||||
|
||||
if (getenv("AFL_DUMP_CODE_COVERAGE")) {
|
||||
|
||||
if (__afl_module_info) {
|
||||
|
||||
int32_t cnt = 0;
|
||||
afl_module_info_t *start = __afl_module_info;
|
||||
|
||||
while (start) {
|
||||
|
||||
++cnt;
|
||||
start = start->next;
|
||||
|
||||
}
|
||||
|
||||
// Allocate per entry enough space for:
|
||||
//
|
||||
// 1. One path
|
||||
// 2. Two pcguard start/stop offsets
|
||||
// 3. Two spaces and a trailing newline
|
||||
//
|
||||
// This is a very conservative allocation so we can just YOLO the rest.
|
||||
size_t bufsize = (PATH_MAX + START_STOP_MAX * 2 + 2 + 1) * cnt + 1;
|
||||
char *buf = malloc(bufsize);
|
||||
char *cur = buf;
|
||||
|
||||
if (!buf) { perror("malloc"); };
|
||||
|
||||
start = __afl_module_info;
|
||||
|
||||
while (start) {
|
||||
|
||||
size_t namelen = strlen(start->name);
|
||||
|
||||
memcpy(cur, start->name, namelen);
|
||||
cur += namelen;
|
||||
*cur = ' ';
|
||||
cur += 1;
|
||||
cur += sprintf(cur, "%u %u", start->start, start->stop);
|
||||
*cur = '\n';
|
||||
cur += 1;
|
||||
|
||||
start = start->next;
|
||||
|
||||
}
|
||||
|
||||
*cur = '\0';
|
||||
|
||||
FILE *f = fopen("modinfo.txt", "w");
|
||||
if (!f) {
|
||||
|
||||
fprintf(stderr, "Error: Could not create modinfo.txt!");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
fprintf(f, "%s\n", buf);
|
||||
fclose(f);
|
||||
|
||||
f = fopen("pcmap.dump", "w");
|
||||
if (!f) {
|
||||
|
||||
fprintf(stderr, "Error: Could not create pcmap.dump!");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
fwrite(__afl_pcmap_ptr, __afl_map_size * sizeof(void *), 1, f);
|
||||
fclose(f);
|
||||
|
||||
fprintf(stderr,
|
||||
"[+] Created modinfo.txt and pcmap.dump for coverage analysis "
|
||||
"purposes. Now run afl-showmap with '-V -b -o covmap.dump'.\n");
|
||||
|
||||
}
|
||||
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
struct sigaction orig_action;
|
||||
sigaction(SIGTERM, NULL, &orig_action);
|
||||
old_sigterm_handler = orig_action.sa_handler;
|
||||
@ -1507,6 +1674,101 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
|
||||
const uintptr_t *pcs_end) {
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init called\n");
|
||||
|
||||
}
|
||||
|
||||
// If for whatever reason, we cannot get dlinfo here, then pc_guard_init also
|
||||
// couldn't get it and we'd end up attributing to the wrong module.
|
||||
Dl_info dlinfo;
|
||||
if (!dladdr(__builtin_return_address(0), &dlinfo)) {
|
||||
|
||||
fprintf(stderr,
|
||||
"WARNING: Ignoring __sanitizer_cov_pcs_init callback due to "
|
||||
"missing module info\n");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
afl_module_info_t *last_module_info = __afl_module_info;
|
||||
while (last_module_info && last_module_info->next) {
|
||||
|
||||
last_module_info = last_module_info->next;
|
||||
|
||||
}
|
||||
|
||||
if (!last_module_info) {
|
||||
|
||||
fprintf(stderr,
|
||||
"ERROR: __sanitizer_cov_pcs_init called with no module info?!\n");
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
last_module_info->pcs_beg = pcs_beg;
|
||||
last_module_info->pcs_end = pcs_end;
|
||||
|
||||
// Now update the pcmap. If this is the last module coming in, after all
|
||||
// pre-loaded code, then this will also map all of our delayed previous
|
||||
// modules.
|
||||
|
||||
if (!__afl_pcmap_ptr) { return; }
|
||||
|
||||
for (afl_module_info_t *mod_info = __afl_module_info; mod_info;
|
||||
mod_info = mod_info->next) {
|
||||
|
||||
if (mod_info->mapped) { continue; }
|
||||
|
||||
PCTableEntry *start = (PCTableEntry *)(mod_info->pcs_beg);
|
||||
PCTableEntry *end = (PCTableEntry *)(mod_info->pcs_end);
|
||||
|
||||
u32 in_module_index = 0;
|
||||
|
||||
if (mod_info->start - in_module_index >= __afl_map_size) {
|
||||
|
||||
fprintf(stderr,
|
||||
"ERROR: __sanitizer_cov_pcs_init out of bounds?! (%u >= %u)\n",
|
||||
mod_info->start, __afl_map_size);
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
while (start < end) {
|
||||
|
||||
uintptr_t PC = start->PC;
|
||||
|
||||
// This is what `GetPreviousInstructionPc` in sanitizer runtime does
|
||||
// for x86/x86-64. Needs more work for ARM and other archs.
|
||||
PC = PC - 1;
|
||||
|
||||
// Calculate relative offset in module
|
||||
PC = PC - mod_info->base_address;
|
||||
|
||||
__afl_pcmap_ptr[mod_info->start + in_module_index] = PC;
|
||||
|
||||
start++;
|
||||
in_module_index++;
|
||||
|
||||
}
|
||||
|
||||
mod_info->mapped = 1;
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init initialized %u PCs\n",
|
||||
in_module_index);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Init callback. Populates instrumentation IDs. Note that we're using
|
||||
ID of 0 as a special value to indicate non-instrumented bits. That may
|
||||
still touch the bitmap, but in a fairly harmless way. */
|
||||
@ -1538,6 +1800,68 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
if (start == stop || *start) { return; }
|
||||
|
||||
u32 *orig_start = start;
|
||||
afl_module_info_t *mod_info = NULL;
|
||||
|
||||
if (getenv("__AFL_CODE_COVERAGE") || getenv("AFL_DUMP_CODE_COVERAGE")) {
|
||||
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (dladdr(__builtin_return_address(0), &dlinfo)) {
|
||||
|
||||
if (__afl_already_initialized_forkserver) {
|
||||
|
||||
fprintf(stderr, "[pcmap] Error: Module was not preloaded: %s\n",
|
||||
dlinfo.dli_fname);
|
||||
|
||||
} else {
|
||||
|
||||
afl_module_info_t *last_module_info = __afl_module_info;
|
||||
while (last_module_info && last_module_info->next) {
|
||||
|
||||
last_module_info = last_module_info->next;
|
||||
|
||||
}
|
||||
|
||||
mod_info = malloc(sizeof(afl_module_info_t));
|
||||
|
||||
mod_info->id = last_module_info ? last_module_info->id + 1 : 0;
|
||||
mod_info->name = strdup(dlinfo.dli_fname);
|
||||
mod_info->base_address = (uintptr_t)dlinfo.dli_fbase;
|
||||
mod_info->start = 0;
|
||||
mod_info->stop = 0;
|
||||
mod_info->pcs_beg = NULL;
|
||||
mod_info->pcs_end = NULL;
|
||||
mod_info->mapped = 0;
|
||||
mod_info->next = NULL;
|
||||
|
||||
if (last_module_info) {
|
||||
|
||||
last_module_info->next = mod_info;
|
||||
|
||||
} else {
|
||||
|
||||
__afl_module_info = mod_info;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "[pcmap] Module: %s Base Address: %p\n",
|
||||
dlinfo.dli_fname, dlinfo.dli_fbase);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "[pcmap] dladdr call failed\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
x = getenv("AFL_INST_RATIO");
|
||||
if (x) {
|
||||
|
||||
@ -1563,17 +1887,27 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
"[-] FATAL: forkserver is already up, but an instrumented dlopen() "
|
||||
"library loaded afterwards. You must AFL_PRELOAD such libraries to "
|
||||
"be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n"
|
||||
"To ignore this set AFL_IGNORE_PROBLEMS=1 but this will be bad for "
|
||||
"coverage.\n");
|
||||
"To ignore this set AFL_IGNORE_PROBLEMS=1 but this will lead to "
|
||||
"ambiguous coverage data.\n"
|
||||
"In addition, you can set AFL_IGNORE_PROBLEMS_COVERAGE=1 to "
|
||||
"ignore the additional coverage instead (use with caution!).\n");
|
||||
abort();
|
||||
|
||||
} else {
|
||||
|
||||
u8 ignore_dso_after_fs = !!getenv("AFL_IGNORE_PROBLEMS_COVERAGE");
|
||||
if (__afl_debug && ignore_dso_after_fs) {
|
||||
|
||||
fprintf(stderr, "Ignoring coverage from dynamically loaded code\n");
|
||||
|
||||
}
|
||||
|
||||
static u32 offset = 5;
|
||||
|
||||
while (start < stop) {
|
||||
|
||||
if (likely(inst_ratio == 100) || R(100) < inst_ratio) {
|
||||
if (!ignore_dso_after_fs &&
|
||||
(likely(inst_ratio == 100) || R(100) < inst_ratio)) {
|
||||
|
||||
*(start++) = offset;
|
||||
|
||||
@ -1615,6 +1949,19 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
}
|
||||
|
||||
if (mod_info) {
|
||||
|
||||
mod_info->start = *orig_start;
|
||||
mod_info->stop = *(stop - 1);
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: [pcmap] Start Index: %u Stop Index: %u\n",
|
||||
mod_info->start, mod_info->stop);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
|
@ -157,6 +157,9 @@ struct afl_cmptrs_pass : afl_base_pass {
|
||||
/* We expect it to be a record type. */
|
||||
if (TREE_CODE(t) != RECORD_TYPE) return false;
|
||||
|
||||
/* The type has an identifier. */
|
||||
if (!TYPE_IDENTIFIER(t)) return false;
|
||||
|
||||
/* The type of the template is basic_string. */
|
||||
if (strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(t)), "basic_string") != 0)
|
||||
return false;
|
||||
@ -201,7 +204,7 @@ struct afl_cmptrs_pass : afl_base_pass {
|
||||
/* Now go back to the first data member. Its type should be a
|
||||
record type named _Alloc_hider. */
|
||||
c = TREE_TYPE(c);
|
||||
if (!c || TREE_CODE(c) != RECORD_TYPE ||
|
||||
if (!c || TREE_CODE(c) != RECORD_TYPE || !TYPE_IDENTIFIER(t) ||
|
||||
strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(c)), "_Alloc_hider") != 0)
|
||||
return false;
|
||||
|
||||
|
@ -584,7 +584,7 @@ bool isInInstrumentList(llvm::Function *F, std::string Filename) {
|
||||
}
|
||||
|
||||
// Calculate the number of average collisions that would occur if all
|
||||
// location IDs would be assigned randomly (like normal afl/afl++).
|
||||
// location IDs would be assigned randomly (like normal afl/AFL++).
|
||||
// This uses the "balls in bins" algorithm.
|
||||
unsigned long long int calculateCollisions(uint32_t edges) {
|
||||
|
||||
|
@ -22,7 +22,9 @@ typedef long double max_align_t;
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
|
@ -53,7 +53,9 @@
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
@ -744,7 +746,7 @@ static void registerAFLdict2filePass(const PassManagerBuilder &,
|
||||
}
|
||||
|
||||
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
|
||||
"afl++ dict2file instrumentation pass",
|
||||
"AFL++ dict2file instrumentation pass",
|
||||
false, false);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass(
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
//#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
// #include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
@ -38,7 +38,9 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
@ -540,7 +542,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
Value *v3Pbitcast = IRB.CreateBitCast(
|
||||
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
|
||||
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
|
||||
Value *v3Pcasted =
|
||||
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
|
||||
args.push_back(v1Pcasted);
|
||||
@ -606,7 +608,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
Value *v3Pbitcast = IRB.CreateBitCast(
|
||||
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
|
||||
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
|
||||
Value *v3Pcasted =
|
||||
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
|
||||
args.push_back(v1Pcasted);
|
||||
|
@ -39,7 +39,9 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
@ -623,7 +623,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
|
||||
Value *icmp = cur_lenchk_IRB.CreateICmpEQ(
|
||||
sizedValue, ConstantInt::get(sizedValue->getType(), i));
|
||||
sizedValue, ConstantInt::get(sizedValue->getType(), i));
|
||||
cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
|
||||
cur_lenchk_bb->getTerminator()->eraseFromParent();
|
||||
|
||||
|
@ -60,7 +60,7 @@ using namespace llvm;
|
||||
|
||||
// uncomment this toggle function verification at each step. horribly slow, but
|
||||
// helps to pinpoint a potential problem in the splitting code.
|
||||
//#define VERIFY_TOO_MUCH 1
|
||||
// #define VERIFY_TOO_MUCH 1
|
||||
|
||||
namespace {
|
||||
|
||||
@ -463,8 +463,12 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst,
|
||||
#else
|
||||
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
|
||||
#endif
|
||||
if (new_pred == CmpInst::ICMP_SGT || new_pred == CmpInst::ICMP_SLT) {
|
||||
|
||||
simplifySignedCompare(icmp_np, M, worklist);
|
||||
|
||||
}
|
||||
|
||||
worklist.push_back(icmp_np);
|
||||
worklist.push_back(icmp_eq);
|
||||
|
||||
return true;
|
||||
@ -740,17 +744,24 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
|
||||
CmpInst *icmp_inv_cmp = nullptr;
|
||||
BasicBlock *inv_cmp_bb =
|
||||
BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb);
|
||||
if (pred == CmpInst::ICMP_UGT || pred == CmpInst::ICMP_SGT ||
|
||||
pred == CmpInst::ICMP_UGE || pred == CmpInst::ICMP_SGE) {
|
||||
if (pred == CmpInst::ICMP_UGT) {
|
||||
|
||||
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
|
||||
op0_high, op1_high);
|
||||
|
||||
} else {
|
||||
} else if (pred == CmpInst::ICMP_ULT) {
|
||||
|
||||
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT,
|
||||
op0_high, op1_high);
|
||||
|
||||
} else {
|
||||
|
||||
// Never gonna appen
|
||||
if (!be_quiet)
|
||||
fprintf(stderr,
|
||||
"Error: split-compare: Equals or signed not removed: %d\n",
|
||||
pred);
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 16
|
||||
|
@ -1 +1 @@
|
||||
2da7f08
|
||||
c8a72dc
|
||||
|
@ -1 +1 @@
|
||||
0569eff8a1
|
||||
a1321713c7
|
||||
|
@ -356,7 +356,7 @@ fi
|
||||
|
||||
if ! command -v "$CROSS" > /dev/null ; then
|
||||
if [ "$CPU_TARGET" = "$(uname -m)" ] ; then
|
||||
echo "[+] Building afl++ qemu support libraries with CC=$CC"
|
||||
echo "[+] Building AFL++ qemu support libraries with CC=$CC"
|
||||
echo "[+] Building libcompcov ..."
|
||||
make -C libcompcov && echo "[+] libcompcov ready"
|
||||
echo "[+] Building unsigaction ..."
|
||||
@ -371,7 +371,7 @@ if ! command -v "$CROSS" > /dev/null ; then
|
||||
echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction"
|
||||
fi
|
||||
else
|
||||
echo "[+] Building afl++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\""
|
||||
echo "[+] Building AFL++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\""
|
||||
echo "[+] Building libcompcov ..."
|
||||
make -C libcompcov CC="$CROSS $CROSS_FLAGS" && echo "[+] libcompcov ready"
|
||||
echo "[+] Building unsigaction ..."
|
||||
|
@ -68,7 +68,11 @@ static int debug_fd = -1;
|
||||
|
||||
#define MAX_MAPPINGS 1024
|
||||
|
||||
static struct mapping { void *st, *en; } __compcov_ro[MAX_MAPPINGS];
|
||||
static struct mapping {
|
||||
|
||||
void *st, *en;
|
||||
|
||||
} __compcov_ro[MAX_MAPPINGS];
|
||||
|
||||
static u32 __compcov_ro_cnt;
|
||||
|
||||
|
@ -1762,7 +1762,7 @@ static FORCEINLINE void *win32direct_mmap(size_t size) {
|
||||
static FORCEINLINE int win32munmap(void *ptr, size_t size) {
|
||||
|
||||
MEMORY_BASIC_INFORMATION minfo;
|
||||
char *cptr = (char *)ptr;
|
||||
char *cptr = (char *)ptr;
|
||||
|
||||
while (size) {
|
||||
|
||||
|
Submodule qemu_mode/qemuafl updated: 0569eff8a1...a1321713c7
572
src/afl-cc.c
572
src/afl-cc.c
@ -31,6 +31,8 @@
|
||||
#include <strings.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if (LLVM_MAJOR - 0 == 0)
|
||||
#undef LLVM_MAJOR
|
||||
@ -76,6 +78,7 @@ enum {
|
||||
INSTRUMENT_OPT_NGRAM = 16,
|
||||
INSTRUMENT_OPT_CALLER = 32,
|
||||
INSTRUMENT_OPT_CTX_K = 64,
|
||||
INSTRUMENT_OPT_CODECOV = 128,
|
||||
|
||||
};
|
||||
|
||||
@ -375,15 +378,316 @@ void parse_fsanitize(char *string) {
|
||||
|
||||
}
|
||||
|
||||
static u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0,
|
||||
shared_linking = 0, preprocessor_only = 0, have_unroll = 0,
|
||||
have_o = 0, have_pic = 0, have_c = 0, partial_linking = 0,
|
||||
non_dash = 0;
|
||||
|
||||
#ifndef MAX_PARAMS_NUM
|
||||
#define MAX_PARAMS_NUM 2048
|
||||
#endif
|
||||
|
||||
static void process_params(u32 argc, char **argv) {
|
||||
|
||||
if (cc_par_cnt + argc >= MAX_PARAMS_NUM) {
|
||||
|
||||
FATAL("Too many command line parameters, please increase MAX_PARAMS_NUM.");
|
||||
|
||||
}
|
||||
|
||||
if (lto_mode && argc > 1) {
|
||||
|
||||
u32 idx;
|
||||
for (idx = 1; idx < argc; idx++) {
|
||||
|
||||
if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
|
||||
|
||||
/* Process the argument list. */
|
||||
|
||||
u8 skip_next = 0;
|
||||
while (--argc) {
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
if (skip_next) {
|
||||
|
||||
skip_next = 0;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (cur[0] != '-') { non_dash = 1; }
|
||||
if (!strncmp(cur, "--afl", 5)) continue;
|
||||
|
||||
if (lto_mode && !strncmp(cur, "-flto=thin", 10)) {
|
||||
|
||||
FATAL(
|
||||
"afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
|
||||
"use afl-clang-fast!");
|
||||
|
||||
}
|
||||
|
||||
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
|
||||
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
|
||||
if (!strncmp(cur, "-fno-unroll", 11)) continue;
|
||||
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
|
||||
!strcmp(cur, "--no-undefined")) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
|
||||
|
||||
if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
|
||||
|
||||
u8 *param = *(argv + 1);
|
||||
if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
|
||||
|
||||
skip_next = 1;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
|
||||
!strncmp(cur, "-stdlib=", 8)) {
|
||||
|
||||
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
|
||||
|
||||
have_instr_list = 1;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
|
||||
strchr(cur, ',')) {
|
||||
|
||||
parse_fsanitize(cur);
|
||||
if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
|
||||
|
||||
} else if ((!strncmp(cur, "-fsanitize=fuzzer-",
|
||||
|
||||
strlen("-fsanitize=fuzzer-")) ||
|
||||
!strncmp(cur, "-fsanitize-coverage",
|
||||
strlen("-fsanitize-coverage"))) &&
|
||||
(strncmp(cur, "sanitize-coverage-allow",
|
||||
strlen("sanitize-coverage-allow")) &&
|
||||
strncmp(cur, "sanitize-coverage-deny",
|
||||
strlen("sanitize-coverage-deny")) &&
|
||||
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
|
||||
|
||||
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
|
||||
|
||||
u8 *afllib = find_object("libAFLDriver.a", argv[0]);
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
|
||||
|
||||
}
|
||||
|
||||
if (!afllib) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF(
|
||||
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
|
||||
"the flags - this will fail!");
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = afllib;
|
||||
|
||||
#ifdef __APPLE__
|
||||
cc_params[cc_par_cnt++] = "-undefined";
|
||||
cc_params[cc_par_cnt++] = "dynamic_lookup";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (need_aflpplib) {
|
||||
|
||||
need_aflpplib = 0;
|
||||
|
||||
} else {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cur, "-m32")) bit_mode = 32;
|
||||
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
|
||||
if (!strcmp(cur, "-m64")) bit_mode = 64;
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
|
||||
asan_set = 1;
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-x")) x_set = 1;
|
||||
if (!strcmp(cur, "-E")) preprocessor_only = 1;
|
||||
if (!strcmp(cur, "-shared")) shared_linking = 1;
|
||||
if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
|
||||
if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
|
||||
if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-r")) partial_linking = 1;
|
||||
if (!strcmp(cur, "--relocatable")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-c")) have_c = 1;
|
||||
|
||||
if (!strncmp(cur, "-O", 2)) have_o = 1;
|
||||
if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
|
||||
|
||||
if (*cur == '@') {
|
||||
|
||||
// response file support.
|
||||
// we have two choices - move everything to the command line or
|
||||
// rewrite the response files to temporary files and delete them
|
||||
// afterwards. We choose the first for easiness.
|
||||
// We do *not* support quotes in the rsp files to cope with spaces in
|
||||
// filenames etc! If you need that then send a patch!
|
||||
u8 *filename = cur + 1;
|
||||
if (debug) { DEBUGF("response file=%s\n", filename); }
|
||||
FILE *f = fopen(filename, "r");
|
||||
struct stat st;
|
||||
|
||||
// Check not found or empty? let the compiler complain if so.
|
||||
if (!f || fstat(fileno(f), &st) < 0 || st.st_size < 1) {
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
u8 *tmpbuf = malloc(st.st_size + 2), *ptr;
|
||||
char **args = malloc(sizeof(char *) * (st.st_size >> 1));
|
||||
int count = 1, cont = 0, cont_act = 0;
|
||||
|
||||
while (fgets(tmpbuf, st.st_size + 1, f)) {
|
||||
|
||||
ptr = tmpbuf;
|
||||
// fprintf(stderr, "1: %s\n", ptr);
|
||||
// no leading whitespace
|
||||
while (isspace(*ptr)) {
|
||||
|
||||
++ptr;
|
||||
cont_act = 0;
|
||||
|
||||
}
|
||||
|
||||
// no comments, no empty lines
|
||||
if (*ptr == '#' || *ptr == '\n' || !*ptr) { continue; }
|
||||
// remove LF
|
||||
if (ptr[strlen(ptr) - 1] == '\n') { ptr[strlen(ptr) - 1] = 0; }
|
||||
// remove CR
|
||||
if (*ptr && ptr[strlen(ptr) - 1] == '\r') { ptr[strlen(ptr) - 1] = 0; }
|
||||
// handle \ at end of line
|
||||
if (*ptr && ptr[strlen(ptr) - 1] == '\\') {
|
||||
|
||||
cont = 1;
|
||||
ptr[strlen(ptr) - 1] = 0;
|
||||
|
||||
}
|
||||
|
||||
// fprintf(stderr, "2: %s\n", ptr);
|
||||
|
||||
// remove whitespace at end
|
||||
while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
|
||||
|
||||
ptr[strlen(ptr) - 1] = 0;
|
||||
cont = 0;
|
||||
|
||||
}
|
||||
|
||||
// fprintf(stderr, "3: %s\n", ptr);
|
||||
if (*ptr) {
|
||||
|
||||
do {
|
||||
|
||||
u8 *value = ptr;
|
||||
while (*ptr && !isspace(*ptr)) {
|
||||
|
||||
++ptr;
|
||||
|
||||
}
|
||||
|
||||
while (*ptr && isspace(*ptr)) {
|
||||
|
||||
*ptr++ = 0;
|
||||
|
||||
}
|
||||
|
||||
if (cont_act) {
|
||||
|
||||
u32 len = strlen(args[count - 1]) + strlen(value) + 1;
|
||||
u8 *tmp = malloc(len);
|
||||
snprintf(tmp, len, "%s%s", args[count - 1], value);
|
||||
free(args[count - 1]);
|
||||
args[count - 1] = tmp;
|
||||
cont_act = 0;
|
||||
|
||||
} else {
|
||||
|
||||
args[count++] = strdup(value);
|
||||
|
||||
}
|
||||
|
||||
} while (*ptr);
|
||||
|
||||
}
|
||||
|
||||
if (cont) {
|
||||
|
||||
cont_act = 1;
|
||||
cont = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (count) { process_params(count, args); }
|
||||
|
||||
// we cannot free args[]
|
||||
free(tmpbuf);
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
|
||||
preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0,
|
||||
have_c = 0, partial_linking = 0;
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
|
||||
cc_params = ck_alloc(MAX_PARAMS_NUM * sizeof(u8 *));
|
||||
|
||||
if (lto_mode) {
|
||||
|
||||
@ -641,10 +945,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
//#if LLVM_MAJOR >= 13
|
||||
// // Use the old pass manager in LLVM 14 which the afl++ passes still
|
||||
// use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
|
||||
//#endif
|
||||
// #if LLVM_MAJOR >= 13
|
||||
// // Use the old pass manager in LLVM 14 which the AFL++ passes still
|
||||
// use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
|
||||
// #endif
|
||||
|
||||
if (lto_mode && !have_c) {
|
||||
|
||||
@ -701,7 +1005,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD) {
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
#if LLVM_MAJOR >= 13
|
||||
#if defined __ANDROID__ || ANDROID
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
@ -718,7 +1022,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
} else {
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
#if LLVM_MAJOR >= 13 /* use new pass manager */
|
||||
#if LLVM_MAJOR < 16
|
||||
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
|
||||
#endif
|
||||
@ -739,21 +1043,35 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
#if LLVM_MAJOR >= 4
|
||||
if (!be_quiet)
|
||||
SAYF(
|
||||
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
|
||||
"Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
|
||||
"enhanced version.\n");
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
#else
|
||||
FATAL("pcguard instrumentation requires llvm 4.0.1+");
|
||||
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
|
||||
|
||||
#if LLVM_MAJOR >= 4
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
|
||||
|
||||
#if LLVM_MAJOR >= 6
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
|
||||
#else
|
||||
FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
FATAL("pcguard instrumentation requires llvm 4.0.1+");
|
||||
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
@ -816,159 +1134,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
/* Inspect the command line parameters. */
|
||||
|
||||
u8 skip_next = 0, non_dash = 0;
|
||||
while (--argc) {
|
||||
process_params(argc, argv);
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
if (skip_next) {
|
||||
|
||||
skip_next = 0;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (cur[0] != '-') { non_dash = 1; }
|
||||
if (!strncmp(cur, "--afl", 5)) continue;
|
||||
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
|
||||
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
|
||||
if (!strncmp(cur, "-fno-unroll", 11)) continue;
|
||||
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
|
||||
!strcmp(cur, "--no-undefined")) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
|
||||
|
||||
if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
|
||||
|
||||
u8 *param = *(argv + 1);
|
||||
if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
|
||||
|
||||
skip_next = 1;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
|
||||
!strncmp(cur, "-stdlib=", 8)) {
|
||||
|
||||
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
|
||||
|
||||
have_instr_list = 1;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
|
||||
strchr(cur, ',')) {
|
||||
|
||||
parse_fsanitize(cur);
|
||||
if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
|
||||
|
||||
} else if ((!strncmp(cur, "-fsanitize=fuzzer-",
|
||||
|
||||
strlen("-fsanitize=fuzzer-")) ||
|
||||
!strncmp(cur, "-fsanitize-coverage",
|
||||
strlen("-fsanitize-coverage"))) &&
|
||||
(strncmp(cur, "sanitize-coverage-allow",
|
||||
strlen("sanitize-coverage-allow")) &&
|
||||
strncmp(cur, "sanitize-coverage-deny",
|
||||
strlen("sanitize-coverage-deny")) &&
|
||||
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
|
||||
|
||||
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
|
||||
|
||||
u8 *afllib = find_object("libAFLDriver.a", argv[0]);
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
|
||||
|
||||
}
|
||||
|
||||
if (!afllib) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF(
|
||||
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
|
||||
"the flags - this will fail!");
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = afllib;
|
||||
|
||||
#ifdef __APPLE__
|
||||
cc_params[cc_par_cnt++] = "-undefined";
|
||||
cc_params[cc_par_cnt++] = "dynamic_lookup";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (need_aflpplib) {
|
||||
|
||||
need_aflpplib = 0;
|
||||
|
||||
} else {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cur, "-m32")) bit_mode = 32;
|
||||
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
|
||||
if (!strcmp(cur, "-m64")) bit_mode = 64;
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
|
||||
asan_set = 1;
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-x")) x_set = 1;
|
||||
if (!strcmp(cur, "-E")) preprocessor_only = 1;
|
||||
if (!strcmp(cur, "-shared")) shared_linking = 1;
|
||||
if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
|
||||
if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
|
||||
if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-r")) partial_linking = 1;
|
||||
if (!strcmp(cur, "--relocatable")) partial_linking = 1;
|
||||
if (!strcmp(cur, "-c")) have_c = 1;
|
||||
|
||||
if (!strncmp(cur, "-O", 2)) have_o = 1;
|
||||
if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; }
|
||||
|
||||
// in case LLVM is installed not via a package manager or "make install"
|
||||
// e.g. compiled download or compiled from github then its ./lib directory
|
||||
@ -1651,13 +1825,17 @@ int main(int argc, char **argv, char **envp) {
|
||||
instrument_mode = INSTRUMENT_CLASSIC;
|
||||
lto_mode = 1;
|
||||
|
||||
} else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
|
||||
} else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) {
|
||||
|
||||
instrument_mode = INSTRUMENT_AFL;
|
||||
else
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("main instrumentation mode already set with %s",
|
||||
instrument_mode_string[instrument_mode]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
|
||||
@ -1672,7 +1850,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
|
||||
strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
|
||||
strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
|
||||
strncasecmp(ptr2, "native", strlen("native")) == 0) {
|
||||
|
||||
if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
@ -1682,6 +1861,24 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
|
||||
strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
|
||||
|
||||
if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) {
|
||||
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
|
||||
setenv("AFL_DONT_OPTIMIZE", "1", 1);
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("main instrumentation mode already set with %s",
|
||||
instrument_mode_string[instrument_mode]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
|
||||
strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
|
||||
|
||||
@ -1843,7 +2040,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
if (!compiler_mode) {
|
||||
|
||||
// lto is not a default because outside of afl-cc RANLIB and AR have to
|
||||
// be set to llvm versions so this would work
|
||||
// be set to LLVM versions so this would work
|
||||
if (have_llvm)
|
||||
compiler_mode = LLVM;
|
||||
else if (have_gcc_plugin)
|
||||
@ -1862,6 +2059,17 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
/* if our PCGUARD implementation is not available then silently switch to
|
||||
native LLVM PCGUARD */
|
||||
if (compiler_mode == CLANG &&
|
||||
(instrument_mode == INSTRUMENT_DEFAULT ||
|
||||
instrument_mode == INSTRUMENT_PCGUARD) &&
|
||||
find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
|
||||
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
|
||||
}
|
||||
|
||||
if (compiler_mode == GCC) {
|
||||
|
||||
if (clang_mode) {
|
||||
@ -1908,12 +2116,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
"-------------|\n"
|
||||
"MODES: NCC PERSIST DICT LAF "
|
||||
"CMPLOG SELECT\n"
|
||||
" [LTO] llvm LTO: %s%s\n"
|
||||
" PCGUARD DEFAULT yes yes yes yes yes "
|
||||
" yes\n"
|
||||
" CLASSIC yes yes yes yes yes "
|
||||
" yes\n"
|
||||
" [LLVM] llvm: %s%s\n"
|
||||
" [LLVM] LLVM: %s%s\n"
|
||||
" PCGUARD %s yes yes module yes yes "
|
||||
"yes\n"
|
||||
" CLASSIC %s no yes module yes yes "
|
||||
@ -1922,16 +2125,21 @@ int main(int argc, char **argv, char **envp) {
|
||||
" - CALLER\n"
|
||||
" - CTX\n"
|
||||
" - NGRAM-{2-16}\n"
|
||||
" [LTO] LLVM LTO: %s%s\n"
|
||||
" PCGUARD DEFAULT yes yes yes yes yes "
|
||||
" yes\n"
|
||||
" CLASSIC yes yes yes yes yes "
|
||||
" 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",
|
||||
have_lto ? "AVAILABLE" : "unavailable!",
|
||||
compiler_mode == LTO ? " [SELECTED]" : "",
|
||||
have_llvm ? "AVAILABLE" : "unavailable!",
|
||||
compiler_mode == LLVM ? " [SELECTED]" : "",
|
||||
have_lto ? "AVAILABLE" : "unavailable!",
|
||||
compiler_mode == LTO ? " [SELECTED]" : "",
|
||||
LLVM_MAJOR >= 7 ? "DEFAULT" : " ",
|
||||
LLVM_MAJOR >= 7 ? " " : "DEFAULT",
|
||||
have_gcc_plugin ? "AVAILABLE" : "unavailable!",
|
||||
@ -1983,7 +2191,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
" (instrumentation/README.lto.md)\n"
|
||||
" PERSIST: persistent mode support [code] (huge speed increase!)\n"
|
||||
" (instrumentation/README.persistent_mode.md)\n"
|
||||
" DICT: dictionary in the target [yes=automatic or llvm module "
|
||||
" DICT: dictionary in the target [yes=automatic or LLVM module "
|
||||
"pass]\n"
|
||||
" (instrumentation/README.lto.md + "
|
||||
"instrumentation/README.llvm.md)\n"
|
||||
@ -2099,6 +2307,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
"bb\n"
|
||||
" AFL_REAL_LD: use this lld linker instead of the compiled in "
|
||||
"path\n"
|
||||
" AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
|
||||
"(used in WAFL mode)\n"
|
||||
"If anything fails - be sure to read README.lto.md!\n");
|
||||
#endif
|
||||
|
||||
@ -2145,6 +2355,15 @@ int main(int argc, char **argv, char **envp) {
|
||||
"AFL_LLVM_CMPLOG and "
|
||||
"AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
|
||||
|
||||
if (LLVM_MAJOR < 13) {
|
||||
|
||||
SAYF(
|
||||
"Warning: It is highly recommended to use at least LLVM version 13 "
|
||||
"(or better, higher) rather than %d!\n\n",
|
||||
LLVM_MAJOR);
|
||||
|
||||
}
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -2239,7 +2458,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
"(requires LLVM 11 or higher)");
|
||||
#endif
|
||||
|
||||
if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
|
||||
if (instrument_opt_mode && instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
|
||||
instrument_mode != INSTRUMENT_CLASSIC)
|
||||
FATAL(
|
||||
"CALLER, CTX and NGRAM instrumentation options can only be used with "
|
||||
"the LLVM CLASSIC instrumentation mode.");
|
||||
|
@ -949,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
|
||||
|
||||
/* Get unix time in milliseconds */
|
||||
|
||||
u64 get_cur_time(void) {
|
||||
inline u64 get_cur_time(void) {
|
||||
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
@ -1298,6 +1298,35 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
|
||||
|
||||
}
|
||||
|
||||
/* Unsafe describe time delta as simple string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *u_simplestring_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
|
||||
|
||||
if (!event_ms) {
|
||||
|
||||
sprintf(buf, "00:00:00");
|
||||
|
||||
} else {
|
||||
|
||||
u64 delta;
|
||||
s32 t_d, t_h, t_m, t_s;
|
||||
|
||||
delta = cur_ms - event_ms;
|
||||
|
||||
t_d = delta / 1000 / 60 / 60 / 24;
|
||||
t_h = (delta / 1000 / 60 / 60) % 24;
|
||||
t_m = (delta / 1000 / 60) % 60;
|
||||
t_s = (delta / 1000) % 60;
|
||||
|
||||
sprintf(buf, "%d:%02d:%02d:%02d", t_d, t_h, t_m, t_s);
|
||||
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
/* Reads the map size from ENV */
|
||||
u32 get_map_size(void) {
|
||||
|
||||
|
@ -226,6 +226,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
/* Settings */
|
||||
fsrv->use_stdin = true;
|
||||
fsrv->no_unlink = false;
|
||||
fsrv->keep_coverage = false;
|
||||
fsrv->coverage_map = NULL;
|
||||
fsrv->exec_tmout = EXEC_TIMEOUT;
|
||||
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
|
||||
fsrv->mem_limit = MEM_LIMIT;
|
||||
@ -276,6 +278,9 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
|
||||
fsrv_to->init_child_func = from->init_child_func;
|
||||
// Note: do not copy ->add_extra_func or ->persistent_record*
|
||||
|
||||
fsrv_to->keep_coverage = false;
|
||||
fsrv_to->coverage_map = NULL;
|
||||
|
||||
list_append(&fsrv_list, fsrv_to);
|
||||
|
||||
}
|
||||
@ -489,7 +494,7 @@ static void report_error_and_exit(int error) {
|
||||
break;
|
||||
case FS_ERROR_OLD_CMPLOG:
|
||||
FATAL(
|
||||
"the -c cmplog target was instrumented with an too old afl++ "
|
||||
"the -c cmplog target was instrumented with an too old AFL++ "
|
||||
"version, you need to recompile it.");
|
||||
break;
|
||||
case FS_ERROR_OLD_CMPLOG_QEMU:
|
||||
@ -987,7 +992,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
|
||||
|
||||
// workaround for recent afl++ versions
|
||||
// workaround for recent AFL++ versions
|
||||
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
|
||||
status = (status & 0xf0ffffff);
|
||||
|
||||
@ -1059,7 +1064,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
FATAL(
|
||||
"Target's coverage map size of %u is larger than the one this "
|
||||
"afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
|
||||
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
|
||||
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
|
||||
"afl-fuzz",
|
||||
tmp_map_size, fsrv->map_size, tmp_map_size);
|
||||
@ -1175,6 +1180,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(fsrv->keep_coverage)) {
|
||||
|
||||
fsrv->coverage_map = ck_alloc(fsrv->map_size);
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1226,7 +1237,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
" - Less likely, there is a horrible bug in the fuzzer. If other "
|
||||
"options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
|
||||
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
|
||||
"tips.\n");
|
||||
|
||||
} else {
|
||||
@ -1271,7 +1282,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
" - Less likely, there is a horrible bug in the fuzzer. If other "
|
||||
"options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
|
||||
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
|
||||
"tips.\n",
|
||||
stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
|
||||
fsrv->mem_limit - 1);
|
||||
@ -1321,7 +1332,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
|
||||
|
||||
"Otherwise there is a horrible bug in the fuzzer.\n"
|
||||
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
|
||||
"Poke the Awesome Fuzzing Discord for troubleshooting tips.\n");
|
||||
|
||||
} else {
|
||||
|
||||
@ -1370,7 +1381,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
" - Less likely, there is a horrible bug in the fuzzer. If other "
|
||||
"options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
|
||||
" fail, poke the Awesome Fuzzing Discord for troubleshooting "
|
||||
"tips.\n",
|
||||
getenv(DEFER_ENV_VAR)
|
||||
? " - You are using deferred forkserver, but __AFL_INIT() is "
|
||||
@ -1407,6 +1418,19 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
|
||||
afl_nyx_runner_kill(fsrv);
|
||||
#endif
|
||||
|
||||
if (unlikely(fsrv->keep_coverage)) {
|
||||
|
||||
// TODO maybe we should write that to out_dir
|
||||
FILE *f = fopen("covmap.dump", "w");
|
||||
if (!f) { PFATAL("creating covmap.dump failed"); }
|
||||
fwrite(fsrv->coverage_map, fsrv->map_size, 1, f);
|
||||
fclose(f);
|
||||
OKF("Wrote coverage map to covmap.dump");
|
||||
ck_free(fsrv->coverage_map);
|
||||
fsrv->coverage_map = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Get the map size from the target forkserver */
|
||||
@ -1565,7 +1589,22 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
|
||||
enum NyxReturnValue ret_val =
|
||||
fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner);
|
||||
|
||||
fsrv->total_execs++;
|
||||
++fsrv->total_execs;
|
||||
|
||||
if (unlikely(fsrv->keep_coverage)) {
|
||||
|
||||
for (u32 i = 0; i < fsrv->map_size; ++i) {
|
||||
|
||||
if (unlikely(fsrv->trace_bits[i]) &&
|
||||
likely(fsrv->coverage_map[i] < 255)) {
|
||||
|
||||
++fsrv->coverage_map[i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (ret_val) {
|
||||
|
||||
|
@ -533,6 +533,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
close(fd);
|
||||
add_to_queue(afl, queue_fn, len, 0);
|
||||
|
||||
if (unlikely(afl->fuzz_mode) && likely(afl->switch_fuzz_mode)) {
|
||||
|
||||
if (afl->afl_env.afl_no_ui) {
|
||||
|
||||
ACTF("New coverage found, switching back to exploration mode.");
|
||||
|
||||
}
|
||||
|
||||
afl->fuzz_mode = 0;
|
||||
|
||||
}
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
if (afl->custom_mutators_count && afl->current_custom_fuzz) {
|
||||
|
||||
|
@ -716,12 +716,25 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
|
||||
}
|
||||
|
||||
// if (getenv("MYTEST")) afl->in_place_resume = 1;
|
||||
|
||||
if (nl_cnt) {
|
||||
|
||||
i = nl_cnt;
|
||||
u32 done = 0;
|
||||
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
i = nl_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
--i;
|
||||
if (unlikely(afl->in_place_resume)) { --i; }
|
||||
|
||||
struct stat st;
|
||||
u8 dfn[PATH_MAX];
|
||||
@ -745,7 +758,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
free(nl[i]); /* not tracked */
|
||||
read_testcases(afl, fn2);
|
||||
ck_free(fn2);
|
||||
continue;
|
||||
goto next_entry;
|
||||
|
||||
}
|
||||
|
||||
@ -754,7 +767,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
|
||||
|
||||
ck_free(fn2);
|
||||
continue;
|
||||
goto next_entry;
|
||||
|
||||
}
|
||||
|
||||
@ -801,21 +814,23 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
next_entry:
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
|
||||
HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
|
||||
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
|
||||
if (unlikely(i == 0)) { done = 1; }
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
*/
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
|
||||
} while (i > 0);
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
|
||||
// if (getenv("MYTEST")) afl->in_place_resume = 0;
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
if (!afl->queued_items && directory == NULL) {
|
||||
@ -897,8 +912,10 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
|
||||
|
||||
SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST,
|
||||
q->len, q->bitmap_size, q->exec_us);
|
||||
SAYF(cGRA
|
||||
" len = %u, map size = %u, exec speed = %llu us, hash = "
|
||||
"%016llx\n" cRST,
|
||||
q->len, q->bitmap_size, q->exec_us, q->exec_cksum);
|
||||
|
||||
}
|
||||
|
||||
@ -995,7 +1012,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
" - Least likely, there is a horrible bug in the fuzzer. If "
|
||||
"other options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for "
|
||||
" fail, poke the Awesome Fuzzing Discord for "
|
||||
"troubleshooting tips.\n",
|
||||
stringify_mem_size(val_buf, sizeof(val_buf),
|
||||
afl->fsrv.mem_limit << 20),
|
||||
@ -1024,7 +1041,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
" - Least likely, there is a horrible bug in the fuzzer. If "
|
||||
"other options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for "
|
||||
" fail, poke the Awesome Fuzzing Discord for "
|
||||
"troubleshooting tips.\n");
|
||||
|
||||
}
|
||||
@ -1153,14 +1170,14 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
u32 duplicates = 0, i;
|
||||
|
||||
for (idx = 0; idx < afl->queued_items; idx++) {
|
||||
for (idx = 0; idx < afl->queued_items - 1; idx++) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
|
||||
|
||||
u32 done = 0;
|
||||
|
||||
for (i = idx + 1;
|
||||
i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) {
|
||||
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
|
||||
|
||||
struct queue_entry *p = afl->queue_buf[i];
|
||||
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
|
||||
@ -1183,6 +1200,13 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
p->disabled = 1;
|
||||
p->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
q->fname, p->fname);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!q->was_fuzzed) {
|
||||
@ -1196,7 +1220,14 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
q->disabled = 1;
|
||||
q->perf_score = 0;
|
||||
|
||||
done = 1;
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
p->fname, q->fname);
|
||||
|
||||
}
|
||||
|
||||
done = 1; // end inner loop because outer loop entry is disabled now
|
||||
|
||||
}
|
||||
|
||||
@ -1511,8 +1542,8 @@ double get_runnable_processes(void) {
|
||||
processes well. */
|
||||
|
||||
FILE *f = fopen("/proc/stat", "r");
|
||||
u8 tmp[1024];
|
||||
u32 val = 0;
|
||||
u8 tmp[1024];
|
||||
u32 val = 0;
|
||||
|
||||
if (!f) { return 0; }
|
||||
|
||||
@ -2195,7 +2226,7 @@ void check_crash_handling(void) {
|
||||
*BSD, so we can just let it slide for now. */
|
||||
|
||||
s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
|
||||
u8 fchar;
|
||||
u8 fchar;
|
||||
|
||||
if (fd < 0) { return; }
|
||||
|
||||
@ -2334,7 +2365,7 @@ void check_cpu_governor(afl_state_t *afl) {
|
||||
FATAL("Suboptimal CPU scaling governor");
|
||||
|
||||
#elif defined __APPLE__
|
||||
u64 min = 0, max = 0;
|
||||
u64 min = 0, max = 0;
|
||||
size_t mlen = sizeof(min);
|
||||
if (afl->afl_env.afl_skip_cpufreq) return;
|
||||
|
||||
|
1012
src/afl-fuzz-one.c
1012
src/afl-fuzz-one.c
File diff suppressed because it is too large
Load Diff
@ -49,11 +49,13 @@ inline u32 select_next_queue_entry(afl_state_t *afl) {
|
||||
|
||||
u32 s = rand_below(afl, afl->queued_items);
|
||||
double p = rand_next_percent(afl);
|
||||
|
||||
/*
|
||||
fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u"
|
||||
" ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p <
|
||||
afl->alias_probability[s] ? s : afl->alias_table[s]);
|
||||
*/
|
||||
|
||||
return (p < afl->alias_probability[s] ? s : afl->alias_table[s]);
|
||||
|
||||
}
|
||||
@ -87,25 +89,28 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
|
||||
|
||||
void create_alias_table(afl_state_t *afl) {
|
||||
|
||||
u32 n = afl->queued_items, i = 0, a, g;
|
||||
u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1;
|
||||
double sum = 0;
|
||||
|
||||
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
|
||||
u32 *Small = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
|
||||
u32 *Large = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
|
||||
|
||||
afl->alias_table =
|
||||
(u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
|
||||
afl->alias_probability = (double *)afl_realloc(
|
||||
(void **)&afl->alias_probability, n * sizeof(double));
|
||||
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
|
||||
int *S = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
|
||||
int *L = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
|
||||
|
||||
if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
|
||||
if (!P || !Small || !Large || !afl->alias_table || !afl->alias_probability) {
|
||||
|
||||
FATAL("could not acquire memory for alias table");
|
||||
|
||||
}
|
||||
|
||||
memset((void *)afl->alias_table, 0, n * sizeof(u32));
|
||||
memset((void *)afl->alias_probability, 0, n * sizeof(double));
|
||||
memset((void *)afl->alias_table, 0, n * sizeof(u32));
|
||||
memset((void *)Small, 0, n * sizeof(u32));
|
||||
memset((void *)Large, 0, n * sizeof(u32));
|
||||
|
||||
if (likely(afl->schedule < RARE)) {
|
||||
|
||||
@ -166,7 +171,15 @@ void create_alias_table(afl_state_t *afl) {
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
// weight is always 0 for disabled entries
|
||||
P[i] = (afl->queue_buf[i]->weight * n) / sum;
|
||||
if (unlikely(afl->queue_buf[i]->disabled)) {
|
||||
|
||||
P[i] = 0;
|
||||
|
||||
} else {
|
||||
|
||||
P[i] = (afl->queue_buf[i]->weight * n) / sum;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -176,60 +189,81 @@ void create_alias_table(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q = afl->queue_buf[i];
|
||||
|
||||
if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); }
|
||||
if (likely(!q->disabled)) {
|
||||
|
||||
sum += q->perf_score;
|
||||
q->perf_score = calculate_score(afl, q);
|
||||
sum += q->perf_score;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
// perf_score is always 0 for disabled entries
|
||||
P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
|
||||
if (unlikely(afl->queue_buf[i]->disabled)) {
|
||||
|
||||
P[i] = 0;
|
||||
|
||||
} else {
|
||||
|
||||
P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int nS = 0, nL = 0, s;
|
||||
for (s = (s32)n - 1; s >= 0; --s) {
|
||||
// Done collecting weightings in P, now create the arrays.
|
||||
|
||||
if (P[s] < 1) {
|
||||
for (s32 j = (s32)(n - 1); j >= 0; j--) {
|
||||
|
||||
S[nS++] = s;
|
||||
if (P[j] < 1) {
|
||||
|
||||
Small[nSmall++] = (u32)j;
|
||||
|
||||
} else {
|
||||
|
||||
L[nL++] = s;
|
||||
Large[nLarge--] = (u32)j;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while (nS && nL) {
|
||||
while (nSmall && nLarge != n - 1) {
|
||||
|
||||
a = S[--nS];
|
||||
g = L[--nL];
|
||||
afl->alias_probability[a] = P[a];
|
||||
afl->alias_table[a] = g;
|
||||
P[g] = P[g] + P[a] - 1;
|
||||
if (P[g] < 1) {
|
||||
u32 small = Small[--nSmall];
|
||||
u32 large = Large[++nLarge];
|
||||
|
||||
S[nS++] = g;
|
||||
afl->alias_probability[small] = P[small];
|
||||
afl->alias_table[small] = large;
|
||||
|
||||
P[large] = P[large] - (1 - P[small]);
|
||||
|
||||
if (P[large] < 1) {
|
||||
|
||||
Small[nSmall++] = large;
|
||||
|
||||
} else {
|
||||
|
||||
L[nL++] = g;
|
||||
Large[nLarge--] = large;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while (nL)
|
||||
afl->alias_probability[L[--nL]] = 1;
|
||||
while (nSmall) {
|
||||
|
||||
while (nS)
|
||||
afl->alias_probability[S[--nS]] = 1;
|
||||
afl->alias_probability[Small[--nSmall]] = 1;
|
||||
|
||||
}
|
||||
|
||||
while (nLarge != n - 1) {
|
||||
|
||||
afl->alias_probability[Large[++nLarge]] = 1;
|
||||
|
||||
}
|
||||
|
||||
afl->reinit_table = 0;
|
||||
|
||||
@ -264,7 +298,7 @@ void create_alias_table(afl_state_t *afl) {
|
||||
*/
|
||||
/*
|
||||
fprintf(stderr, " entry alias probability perf_score weight
|
||||
filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
|
||||
filename\n"); for (i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
|
||||
%0.9f %0.9f %s\n", i, afl->alias_table[i], afl->alias_probability[i],
|
||||
afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight,
|
||||
afl->queue_buf[i]->fname);
|
||||
@ -578,7 +612,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
}
|
||||
|
||||
if (likely(q->len > 4)) afl->ready_for_splicing_count++;
|
||||
if (likely(q->len > 4)) { ++afl->ready_for_splicing_count; }
|
||||
|
||||
++afl->queued_items;
|
||||
++afl->active_items;
|
||||
|
@ -28,8 +28,8 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "cmplog.h"
|
||||
|
||||
//#define _DEBUG
|
||||
//#define CMPLOG_INTROSPECTION
|
||||
// #define _DEBUG
|
||||
// #define CMPLOG_INTROSPECTION
|
||||
|
||||
// CMP attribute enum
|
||||
enum {
|
||||
@ -379,7 +379,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
|
||||
|
||||
}
|
||||
|
||||
if (++afl->stage_cur % screen_update == 0) { show_stats(afl); };
|
||||
if (unlikely(++afl->stage_cur % screen_update == 0)) { show_stats(afl); };
|
||||
|
||||
}
|
||||
|
||||
@ -571,7 +571,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
|
||||
|
||||
}
|
||||
|
||||
//#ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
// #ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
static int strntoll(const char *str, size_t sz, char **end, int base,
|
||||
long long *out) {
|
||||
|
||||
@ -771,7 +771,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
|
||||
|
||||
#endif
|
||||
|
||||
//#endif
|
||||
// #endif
|
||||
|
||||
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
u64 pattern, u64 repl, u64 o_pattern,
|
||||
@ -790,7 +790,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
|
||||
u32 its_len = MIN(len - idx, taint_len);
|
||||
|
||||
if (afl->fsrv.total_execs - last_update > screen_update) {
|
||||
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
|
||||
|
||||
show_stats(afl);
|
||||
last_update = afl->fsrv.total_execs;
|
||||
@ -803,8 +803,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
// o_pattern, pattern, repl, changed_val, idx, taint_len,
|
||||
// hshape, attr);
|
||||
|
||||
//#ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
|
||||
// #ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
|
||||
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
|
||||
|
||||
u8 *endptr;
|
||||
@ -1120,7 +1120,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
|
||||
}
|
||||
|
||||
//#endif
|
||||
// #endif
|
||||
|
||||
// we only allow this for ascii2integer (above) so leave if this is the case
|
||||
if (unlikely(pattern == o_pattern)) { return 0; }
|
||||
@ -1275,7 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
// 16 = modified float, 32 = modified integer (modified = wont match
|
||||
// in original buffer)
|
||||
|
||||
//#ifdef CMPLOG_SOLVE_ARITHMETIC
|
||||
// #ifdef CMPLOG_SOLVE_ARITHMETIC
|
||||
if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
|
||||
|
||||
return 0;
|
||||
@ -1440,8 +1440,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
||||
|
||||
}
|
||||
|
||||
//#endif /*
|
||||
// CMPLOG_SOLVE_ARITHMETIC
|
||||
// #endif /*
|
||||
// CMPLOG_SOLVE_ARITHMETIC
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1455,7 +1455,7 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
|
||||
u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
|
||||
u32 len, u8 do_reverse, u8 lvl, u8 *status) {
|
||||
|
||||
if (afl->fsrv.total_execs - last_update > screen_update) {
|
||||
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
|
||||
|
||||
show_stats(afl);
|
||||
last_update = afl->fsrv.total_execs;
|
||||
@ -1948,11 +1948,11 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
|
||||
#ifndef CMPLOG_COMBINE
|
||||
(void)(cbuf);
|
||||
#endif
|
||||
//#ifndef CMPLOG_SOLVE_TRANSFORM
|
||||
// (void)(changed_val);
|
||||
//#endif
|
||||
// #ifndef CMPLOG_SOLVE_TRANSFORM
|
||||
// (void)(changed_val);
|
||||
// #endif
|
||||
|
||||
if (afl->fsrv.total_execs - last_update > screen_update) {
|
||||
if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
|
||||
|
||||
show_stats(afl);
|
||||
last_update = afl->fsrv.total_execs;
|
||||
@ -1988,10 +1988,10 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
|
||||
|
||||
if (l0 >= 0x80 || ol0 >= 0x80) {
|
||||
|
||||
l0 -= 0x80;
|
||||
l1 -= 0x80;
|
||||
ol0 -= 0x80;
|
||||
ol1 -= 0x80;
|
||||
if (l0 >= 0x80) { l0 -= 0x80; }
|
||||
if (l1 >= 0x80) { l1 -= 0x80; }
|
||||
if (ol0 >= 0x80) { ol0 -= 0x80; }
|
||||
if (ol1 >= 0x80) { ol1 -= 0x80; }
|
||||
|
||||
}
|
||||
|
||||
@ -2059,7 +2059,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
|
||||
|
||||
for (i = 0; i < its_len; ++i) {
|
||||
|
||||
if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
|
||||
if ((pattern[i] != buf[idx + i] || o_pattern[i] != orig_buf[idx + i]) ||
|
||||
*status == 1) {
|
||||
|
||||
break;
|
||||
@ -2418,7 +2418,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
|
||||
|
||||
}
|
||||
|
||||
//#endif
|
||||
// #endif
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2592,6 +2592,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
|
||||
// shape_len), check_if_text_buf((u8 *)&o->v1, shape_len), v0_len,
|
||||
// o->v0, v1_len, o->v1);
|
||||
|
||||
// Note that this check differs from the line 1901, for RTN we are more
|
||||
// opportunistic for adding to the dictionary than cmps
|
||||
if (!memcmp(o->v0, orig_o->v0, v0_len) ||
|
||||
(!found_one || check_if_text_buf((u8 *)&o->v0, v0_len) == v0_len))
|
||||
maybe_add_auto(afl, o->v0, v0_len);
|
||||
@ -2818,9 +2820,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
|
||||
|
||||
} else if ((lvl & LVL1)
|
||||
|
||||
//#ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
// #ifdef CMPLOG_SOLVE_TRANSFORM
|
||||
|| ((lvl & LVL3) && afl->cmplog_enable_transform)
|
||||
//#endif
|
||||
// #endif
|
||||
) {
|
||||
|
||||
if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
|
||||
|
@ -135,10 +135,19 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
|
||||
|
||||
if (new_mem != *mem && new_mem != NULL && new_size > 0) {
|
||||
|
||||
u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
|
||||
new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
|
||||
if (unlikely(!new_buf)) { PFATAL("alloc"); }
|
||||
memcpy(new_buf, new_mem, new_size);
|
||||
|
||||
/* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory
|
||||
prior post-processing in new_mem to restore it later */
|
||||
if (unlikely(afl->afl_env.afl_post_process_keep_original)) {
|
||||
|
||||
new_mem = *mem;
|
||||
|
||||
}
|
||||
|
||||
*mem = new_buf;
|
||||
memcpy(*mem, new_mem, new_size);
|
||||
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
|
||||
|
||||
}
|
||||
@ -162,7 +171,18 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
|
||||
|
||||
/* everything as planned. use the potentially new data. */
|
||||
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
|
||||
len = new_size;
|
||||
|
||||
if (likely(!afl->afl_env.afl_post_process_keep_original)) {
|
||||
|
||||
len = new_size;
|
||||
|
||||
} else {
|
||||
|
||||
/* restore the original memory which was saved in new_mem */
|
||||
*mem = new_mem;
|
||||
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
afl->cmplog_lvl = 2;
|
||||
afl->min_length = 1;
|
||||
afl->max_length = MAX_FILE;
|
||||
afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000;
|
||||
#ifndef NO_SPLICING
|
||||
afl->use_splicing = 1;
|
||||
#endif
|
||||
@ -394,6 +395,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
|
||||
afl->afl_env.afl_statsd =
|
||||
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
|
||||
|
||||
} else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL",
|
||||
|
||||
afl_environment_variable_len)) {
|
||||
|
||||
afl->afl_env.afl_post_process_keep_original =
|
||||
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
|
||||
|
||||
} else if (!strncmp(env, "AFL_TMPDIR",
|
||||
|
||||
afl_environment_variable_len)) {
|
||||
|
@ -27,6 +27,45 @@
|
||||
#include "envs.h"
|
||||
#include <limits.h>
|
||||
|
||||
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
|
||||
"finished..."};
|
||||
|
||||
char *get_fuzzing_state(afl_state_t *afl) {
|
||||
|
||||
u64 cur_ms = get_cur_time();
|
||||
u64 last_find = cur_ms - afl->last_find_time;
|
||||
u64 cur_run_time = cur_ms - afl->start_time;
|
||||
u64 cur_total_run_time = afl->prev_run_time + cur_run_time;
|
||||
|
||||
if (unlikely(cur_run_time < 60 * 3 * 1000 ||
|
||||
cur_total_run_time < 60 * 5 * 1000)) {
|
||||
|
||||
return fuzzing_state[0];
|
||||
|
||||
} else {
|
||||
|
||||
u64 last_find_100 = 100 * last_find;
|
||||
u64 percent_cur = last_find_100 / cur_run_time;
|
||||
u64 percent_total = last_find_100 / cur_total_run_time;
|
||||
|
||||
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
|
||||
|
||||
return fuzzing_state[3];
|
||||
|
||||
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
|
||||
|
||||
return fuzzing_state[2];
|
||||
|
||||
} else {
|
||||
|
||||
return fuzzing_state[1];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write fuzzer setup file */
|
||||
|
||||
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
|
||||
@ -1282,7 +1321,11 @@ void show_stats_normal(afl_state_t *afl) {
|
||||
}
|
||||
|
||||
/* Last line */
|
||||
SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1);
|
||||
|
||||
SAYF(SET_G1 "\n" bSTG bLB bH cCYA bSTOP " strategy:" cPIN
|
||||
" %s " bSTG bH10 cCYA bSTOP " state:" cPIN
|
||||
" %s " bSTG bH2 bRB bSTOP cRST RESET_G1,
|
||||
afl->fuzz_mode == 0 ? "explore" : "exploit", get_fuzzing_state(afl));
|
||||
|
||||
#undef IB
|
||||
|
||||
@ -2260,7 +2303,12 @@ void show_init_stats(afl_state_t *afl) {
|
||||
stringify_int(IB(0), min_us), stringify_int(IB(1), max_us),
|
||||
stringify_int(IB(2), avg_us));
|
||||
|
||||
if (afl->timeout_given != 1) {
|
||||
if (afl->timeout_given == 3) {
|
||||
|
||||
ACTF("Applying timeout settings from resumed session (%u ms).",
|
||||
afl->fsrv.exec_tmout);
|
||||
|
||||
} else if (afl->timeout_given != 1) {
|
||||
|
||||
/* Figure out the appropriate timeout. The basic idea is: 5x average or
|
||||
1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second.
|
||||
@ -2302,11 +2350,6 @@ void show_init_stats(afl_state_t *afl) {
|
||||
|
||||
afl->timeout_given = 1;
|
||||
|
||||
} else if (afl->timeout_given == 3) {
|
||||
|
||||
ACTF("Applying timeout settings from resumed session (%u ms).",
|
||||
afl->fsrv.exec_tmout);
|
||||
|
||||
} else {
|
||||
|
||||
ACTF("-t option specified. We'll use an exec timeout of %u ms.",
|
||||
|
289
src/afl-fuzz.c
289
src/afl-fuzz.c
@ -124,10 +124,19 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"
|
||||
|
||||
"Required parameters:\n"
|
||||
" -i dir - input directory with test cases\n"
|
||||
" -i dir - input directory with test cases (or '-' to resume, "
|
||||
"also see \n"
|
||||
" AFL_AUTORESUME)\n"
|
||||
" -o dir - output directory for fuzzer findings\n\n"
|
||||
|
||||
"Execution control settings:\n"
|
||||
" -P strategy - set fix mutation strategy: explore (focus on new "
|
||||
"coverage),\n"
|
||||
" exploit (focus on triggering crashes). You can also "
|
||||
"set a\n"
|
||||
" number of seconds after without any finds it switches "
|
||||
"to\n"
|
||||
" exploit mode, and back on new coverage (default: %u)\n"
|
||||
" -p schedule - power schedules compute a seed's performance score:\n"
|
||||
" fast(default), explore, exploit, seek, rare, mmopt, "
|
||||
"coe, lin\n"
|
||||
@ -156,6 +165,8 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"\n"
|
||||
|
||||
"Mutator settings:\n"
|
||||
" -a - target input format, \"text\" or \"binary\" (default: "
|
||||
"generic)\n"
|
||||
" -g minlength - set min length of generated fuzz input (default: 1)\n"
|
||||
" -G maxlength - set max length of generated fuzz input (default: "
|
||||
"%lu)\n"
|
||||
@ -211,7 +222,8 @@ static void usage(u8 *argv0, int more_help) {
|
||||
" -e ext - file extension for the fuzz test input file (if "
|
||||
"needed)\n"
|
||||
"\n",
|
||||
argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
|
||||
argv0, STRATEGY_SWITCH_TIME, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE,
|
||||
FOREIGN_SYNCS_MAX);
|
||||
|
||||
if (more_help > 1) {
|
||||
|
||||
@ -259,6 +271,8 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
|
||||
"AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n"
|
||||
"AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n"
|
||||
" ignore those libs for coverage\n"
|
||||
"AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n"
|
||||
"AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
|
||||
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
|
||||
@ -292,6 +306,8 @@ static void usage(u8 *argv0, int more_help) {
|
||||
|
||||
PERSISTENT_MSG
|
||||
|
||||
"AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n"
|
||||
" but execute the post-processed one\n"
|
||||
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
||||
"AFL_TARGET_ENV: pass extra environment variables to target\n"
|
||||
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
|
||||
@ -326,7 +342,7 @@ static void usage(u8 *argv0, int more_help) {
|
||||
}
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
|
||||
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
|
||||
(char *)PYTHON_VERSION);
|
||||
#else
|
||||
SAYF("Compiled without Python module support.\n");
|
||||
@ -489,14 +505,63 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
|
||||
|
||||
while (
|
||||
(opt = getopt(
|
||||
argc, argv,
|
||||
"+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) >
|
||||
0) {
|
||||
// still available: HjJkKqruvwz
|
||||
while ((opt = getopt(argc, argv,
|
||||
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
|
||||
"T:UV:WXx:YZ")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'a':
|
||||
|
||||
if (!stricmp(optarg, "text") || !stricmp(optarg, "ascii") ||
|
||||
!stricmp(optarg, "txt") || !stricmp(optarg, "asc")) {
|
||||
|
||||
afl->input_mode = 1;
|
||||
|
||||
} else if (!stricmp(optarg, "bin") || !stricmp(optarg, "binary")) {
|
||||
|
||||
afl->input_mode = 2;
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("-a input mode needs to be \"text\" or \"binary\".");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
if (!stricmp(optarg, "explore") || !stricmp(optarg, "exploration")) {
|
||||
|
||||
afl->fuzz_mode = 0;
|
||||
afl->switch_fuzz_mode = 0;
|
||||
|
||||
} else if (!stricmp(optarg, "exploit") ||
|
||||
|
||||
!stricmp(optarg, "exploitation")) {
|
||||
|
||||
afl->fuzz_mode = 1;
|
||||
afl->switch_fuzz_mode = 0;
|
||||
|
||||
} else {
|
||||
|
||||
if ((afl->switch_fuzz_mode = (u32)atoi(optarg)) > INT_MAX) {
|
||||
|
||||
FATAL(
|
||||
"Parameter for option -P must be \"explore\", \"exploit\" or a "
|
||||
"number!");
|
||||
|
||||
} else {
|
||||
|
||||
afl->switch_fuzz_mode *= 1000;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
afl->min_length = atoi(optarg);
|
||||
break;
|
||||
@ -1216,6 +1281,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
WARNF(
|
||||
"Note that the MOpt mode is not maintained and is not as effective "
|
||||
"as normal havoc mode.");
|
||||
|
||||
} break;
|
||||
|
||||
case 'h':
|
||||
@ -1276,16 +1345,16 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
|
||||
|
||||
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
|
||||
"Eißfeldt, Andrea Fioraldi and Dominik Maier");
|
||||
OKF("afl++ is open source, get it at "
|
||||
OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
|
||||
"Fioraldi and Heiko \"hexcoder\" Eißfeldt");
|
||||
OKF("AFL++ is open source, get it at "
|
||||
"https://github.com/AFLplusplus/AFLplusplus");
|
||||
OKF("NOTE: afl++ >= v3 has changed defaults and behaviours - see README.md");
|
||||
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
|
||||
|
||||
#ifdef __linux__
|
||||
if (afl->fsrv.nyx_mode) {
|
||||
|
||||
OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
|
||||
OKF("AFL++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
|
||||
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
|
||||
|
||||
}
|
||||
@ -1525,29 +1594,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
|
||||
|
||||
if (afl->custom_only) {
|
||||
|
||||
FATAL("Custom mutators are incompatible with MOpt (-L)");
|
||||
|
||||
}
|
||||
|
||||
u32 custom_fuzz = 0;
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
|
||||
if (el->afl_custom_fuzz) { custom_fuzz = 1; }
|
||||
|
||||
});
|
||||
|
||||
if (custom_fuzz) {
|
||||
|
||||
WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (afl->afl_env.afl_max_det_extras) {
|
||||
|
||||
s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
|
||||
@ -1764,16 +1810,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
check_if_tty(afl);
|
||||
if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
|
||||
|
||||
if (afl->afl_env.afl_custom_mutator_only) {
|
||||
|
||||
/* This ensures we don't proceed to havoc/splice */
|
||||
afl->custom_only = 1;
|
||||
|
||||
/* Ensure we also skip all deterministic steps */
|
||||
afl->skip_deterministic = 1;
|
||||
|
||||
}
|
||||
|
||||
get_core_count(afl);
|
||||
|
||||
atexit(at_exit);
|
||||
@ -1822,8 +1858,107 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
|
||||
#endif
|
||||
|
||||
if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) {
|
||||
|
||||
setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1);
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) {
|
||||
|
||||
setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1);
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {
|
||||
|
||||
u8 envbuf[8096] = "", tmpbuf[8096] = "";
|
||||
for (s32 i = optind + 1; i < argc; ++i) {
|
||||
|
||||
strcpy(tmpbuf, envbuf);
|
||||
if (strchr(argv[i], ' ') && !strchr(argv[i], '"') &&
|
||||
!strchr(argv[i], '\'')) {
|
||||
|
||||
if (!strchr(argv[i], '\'')) {
|
||||
|
||||
snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]);
|
||||
|
||||
} else {
|
||||
|
||||
snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1);
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_CUSTOM_INFO_OUT")) {
|
||||
|
||||
setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR
|
||||
|
||||
}
|
||||
|
||||
setup_custom_mutators(afl);
|
||||
|
||||
if (afl->afl_env.afl_custom_mutator_only) {
|
||||
|
||||
if (!afl->custom_mutators_count) {
|
||||
|
||||
if (afl->shm.cmplog_mode) {
|
||||
|
||||
WARNF(
|
||||
"No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
|
||||
"pointless and only allowed now to allow experiments with CMPLOG.");
|
||||
|
||||
} else {
|
||||
|
||||
FATAL(
|
||||
"No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This ensures we don't proceed to havoc/splice */
|
||||
afl->custom_only = 1;
|
||||
|
||||
/* Ensure we also skip all deterministic steps */
|
||||
afl->skip_deterministic = 1;
|
||||
|
||||
}
|
||||
|
||||
if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
|
||||
|
||||
if (afl->custom_only) {
|
||||
|
||||
FATAL("Custom mutators are incompatible with MOpt (-L)");
|
||||
|
||||
}
|
||||
|
||||
u32 custom_fuzz = 0;
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
|
||||
if (el->afl_custom_fuzz) { custom_fuzz = 1; }
|
||||
|
||||
});
|
||||
|
||||
if (custom_fuzz) {
|
||||
|
||||
WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_setup_file(afl, argc, argv);
|
||||
|
||||
setup_cmdline_file(afl, argv + optind);
|
||||
@ -1975,6 +2110,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
|
||||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
|
||||
@ -1986,6 +2122,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->first_trace = ck_realloc(afl->first_trace, map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
|
||||
|
||||
if (old_map_size < map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
afl->argv = use_argv;
|
||||
@ -2013,6 +2161,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes", new_map_size);
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
@ -2025,6 +2174,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
afl->fsrv.map_size = new_map_size;
|
||||
@ -2075,6 +2236,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
@ -2087,6 +2249,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
@ -2209,6 +2383,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
max_ms = afl->queue_buf[entry]->exec_us;
|
||||
|
||||
afl->fsrv.exec_tmout = max_ms;
|
||||
afl->timeout_given = 1;
|
||||
|
||||
}
|
||||
|
||||
@ -2578,13 +2753,31 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
|
||||
|
||||
u64 cur_time = get_cur_time();
|
||||
|
||||
if (likely(afl->switch_fuzz_mode && afl->fuzz_mode == 0) &&
|
||||
unlikely(cur_time > afl->last_find_time + afl->switch_fuzz_mode)) {
|
||||
|
||||
if (afl->afl_env.afl_no_ui) {
|
||||
|
||||
ACTF(
|
||||
"No new coverage found for %llu seconds, switching to exploitation "
|
||||
"strategy.",
|
||||
afl->switch_fuzz_mode / 1000);
|
||||
|
||||
}
|
||||
|
||||
afl->fuzz_mode = 1;
|
||||
|
||||
}
|
||||
|
||||
if (likely(!afl->stop_soon && afl->sync_id)) {
|
||||
|
||||
if (likely(afl->skip_deterministic)) {
|
||||
|
||||
if (unlikely(afl->is_main_node)) {
|
||||
|
||||
if (unlikely(get_cur_time() >
|
||||
if (unlikely(cur_time >
|
||||
(afl->sync_time >> 1) + afl->last_sync_time)) {
|
||||
|
||||
if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
|
||||
@ -2597,7 +2790,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
} else {
|
||||
|
||||
if (unlikely(get_cur_time() > afl->sync_time + afl->last_sync_time)) {
|
||||
if (unlikely(cur_time > afl->sync_time + afl->last_sync_time)) {
|
||||
|
||||
if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
american fuzzy lop++ - wrapper for llvm 11+ lld
|
||||
-----------------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de> for afl++
|
||||
Written by Marc Heuse <mh@mh-sec.de> for AFL++
|
||||
|
||||
Maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
|
||||
@ -210,7 +210,7 @@ static void edit_params(int argc, char **argv) {
|
||||
|
||||
if (strcmp(argv[i], "--afl") == 0) {
|
||||
|
||||
if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
|
||||
if (!be_quiet) OKF("AFL++ test command line flag detected, exiting.");
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
@ -30,8 +30,10 @@
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
#define AFL_SHOWMAP
|
||||
|
||||
#include "config.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
@ -62,15 +64,20 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static afl_state_t *afl;
|
||||
|
||||
static char *stdin_file; /* stdin file */
|
||||
|
||||
static u8 *in_dir = NULL, /* input folder */
|
||||
*out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
|
||||
*out_file = NULL, /* output file or directory */
|
||||
*at_file = NULL, /* Substitution string for @@ */
|
||||
*in_filelist = NULL; /* input file list */
|
||||
|
||||
static u8 outfile[PATH_MAX];
|
||||
|
||||
static u8 *in_data, /* Input data */
|
||||
*coverage_map; /* Coverage map */
|
||||
static u8 *in_data; /* Input data */
|
||||
|
||||
static u8 *coverage_map; /* Coverage map */
|
||||
|
||||
static u64 total; /* tuple content information */
|
||||
static u32 tcnt, highest; /* tuple content information */
|
||||
@ -91,7 +98,8 @@ static bool quiet_mode, /* Hide non-essential messages? */
|
||||
no_classify, /* do not classify counts */
|
||||
debug, /* debug mode */
|
||||
print_filenames, /* print the current filename */
|
||||
wait_for_gdb;
|
||||
wait_for_gdb, /* wait for gdb to allow attaching */
|
||||
code_cov; /* code coverage cmdline parameter */
|
||||
|
||||
static volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||
child_crashed; /* Child crashed? */
|
||||
@ -105,8 +113,9 @@ static sharedmem_t *shm_fuzz;
|
||||
|
||||
static const u8 count_class_human[256] = {
|
||||
|
||||
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4,
|
||||
[8] = 5, [16] = 6, [32] = 7, [128] = 8
|
||||
[0] = 0, [1] = 1, [2] = 2, [3] = 3,
|
||||
[4 ... 7] = 4, [8 ... 15] = 5, [16 ... 31] = 6, [32 ... 127] = 7,
|
||||
[128 ... 255] = 8
|
||||
|
||||
};
|
||||
|
||||
@ -136,7 +145,39 @@ static void kill_child() {
|
||||
|
||||
}
|
||||
|
||||
static void classify_counts(afl_forkserver_t *fsrv) {
|
||||
/* dummy functions */
|
||||
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
|
||||
|
||||
(void)afl;
|
||||
(void)mem;
|
||||
return a + b;
|
||||
|
||||
}
|
||||
|
||||
void show_stats(afl_state_t *afl) {
|
||||
|
||||
(void)afl;
|
||||
|
||||
}
|
||||
|
||||
void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
|
||||
|
||||
(void)afl;
|
||||
(void)q;
|
||||
|
||||
}
|
||||
|
||||
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
|
||||
u32 i) {
|
||||
|
||||
(void)afl;
|
||||
(void)fsrv;
|
||||
(void)i;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void classify_counts(afl_forkserver_t *fsrv) {
|
||||
|
||||
u8 *mem = fsrv->trace_bits;
|
||||
const u8 *map = binary_mode ? count_class_binary : count_class_human;
|
||||
@ -205,7 +246,15 @@ static void analyze_results(afl_forkserver_t *fsrv) {
|
||||
|
||||
total += fsrv->trace_bits[i];
|
||||
if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
|
||||
if (!coverage_map[i]) { coverage_map[i] = 1; }
|
||||
if (code_cov) {
|
||||
|
||||
if (coverage_map[i] < 255 && fsrv->trace_bits[i]) { coverage_map[i]++; }
|
||||
|
||||
} else {
|
||||
|
||||
coverage_map[i] |= fsrv->trace_bits[i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -290,7 +339,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
|
||||
|
||||
if (cmin_mode) {
|
||||
|
||||
fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
|
||||
fprintf(f, "%u%03u\n", i, fsrv->trace_bits[i]);
|
||||
|
||||
} else {
|
||||
|
||||
@ -308,12 +357,143 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
static u32 write_results_to_file32(u32 *map, u8 *outfile) {
|
||||
|
||||
s32 fd;
|
||||
u32 i, ret = 0;
|
||||
|
||||
if (!outfile || !*outfile) {
|
||||
|
||||
FATAL("Output filename not set (Bug in AFL++?)");
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(outfile, "/dev/", 5)) {
|
||||
|
||||
fd = open(outfile, O_WRONLY);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to open '%s'", out_file); }
|
||||
|
||||
} else if (!strcmp(outfile, "-")) {
|
||||
|
||||
fd = dup(1);
|
||||
if (fd < 0) { PFATAL("Unable to open stdout"); }
|
||||
|
||||
} else {
|
||||
|
||||
unlink(outfile); /* Ignore errors */
|
||||
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
|
||||
|
||||
}
|
||||
|
||||
if (binary_mode) {
|
||||
|
||||
for (i = 0; i < map_size; i++) {
|
||||
|
||||
if (map[i]) { ret++; }
|
||||
|
||||
}
|
||||
|
||||
ck_write(fd, map, map_size, outfile);
|
||||
close(fd);
|
||||
|
||||
} else {
|
||||
|
||||
FILE *f = fdopen(fd, "w");
|
||||
|
||||
if (!f) { PFATAL("fdopen() failed"); }
|
||||
|
||||
for (i = 0; i < map_size; i++) {
|
||||
|
||||
if (!map[i]) { continue; }
|
||||
ret++;
|
||||
|
||||
total += map[i];
|
||||
if (highest < map[i]) { highest = map[i]; }
|
||||
|
||||
fprintf(f, "%06u:%u\n", i, map[i]);
|
||||
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) {
|
||||
|
||||
static u8 buf[MAX_FILE];
|
||||
u32 sent = 0;
|
||||
|
||||
if (unlikely(afl->custom_mutators_count)) {
|
||||
|
||||
ssize_t new_size = len;
|
||||
u8 *new_mem = mem;
|
||||
u8 *new_buf = NULL;
|
||||
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
|
||||
if (el->afl_custom_post_process) {
|
||||
|
||||
new_size =
|
||||
el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
|
||||
|
||||
if (unlikely(!new_buf || new_size <= 0)) {
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
new_mem = new_buf;
|
||||
len = new_size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (new_mem != mem && new_mem != NULL) {
|
||||
|
||||
mem = buf;
|
||||
memcpy(mem, new_mem, new_size);
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->custom_mutators_count)) {
|
||||
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
|
||||
if (el->afl_custom_fuzz_send) {
|
||||
|
||||
el->afl_custom_fuzz_send(el->data, mem, len);
|
||||
sent = 1;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); }
|
||||
|
||||
}
|
||||
|
||||
/* Execute target application. */
|
||||
|
||||
static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
|
||||
u32 len) {
|
||||
|
||||
afl_fsrv_write_to_testcase(fsrv, mem, len);
|
||||
pre_afl_fsrv_write_to_testcase(fsrv, mem, len);
|
||||
|
||||
if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
|
||||
|
||||
@ -324,9 +504,9 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->trace_bits[0] == 1) {
|
||||
if (fsrv->trace_bits[0]) {
|
||||
|
||||
fsrv->trace_bits[0] = 0;
|
||||
fsrv->trace_bits[0] -= 1;
|
||||
have_coverage = true;
|
||||
|
||||
} else {
|
||||
@ -555,9 +735,9 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->trace_bits[0] == 1) {
|
||||
if (fsrv->trace_bits[0]) {
|
||||
|
||||
fsrv->trace_bits[0] = 0;
|
||||
fsrv->trace_bits[0] -= 1;
|
||||
have_coverage = true;
|
||||
|
||||
} else {
|
||||
@ -781,6 +961,103 @@ u32 execute_testcases(u8 *dir) {
|
||||
|
||||
}
|
||||
|
||||
u32 execute_testcases_filelist(u8 *fn) {
|
||||
|
||||
u32 done = 0;
|
||||
u8 buf[4096];
|
||||
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
|
||||
FILE *f;
|
||||
|
||||
if (!be_quiet) { ACTF("Reading from '%s'...", fn); }
|
||||
|
||||
if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); }
|
||||
|
||||
while (fgets(buf, sizeof(buf), f) != NULL) {
|
||||
|
||||
struct stat st;
|
||||
u8 *fn2 = buf, *fn3;
|
||||
|
||||
while (*fn2 == ' ') {
|
||||
|
||||
++fn2;
|
||||
|
||||
}
|
||||
|
||||
while (*fn2 &&
|
||||
(fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' ||
|
||||
fn2[strlen(fn2) - 1] == ' ')) {
|
||||
|
||||
fn2[strlen(fn2) - 1] = 0;
|
||||
|
||||
}
|
||||
|
||||
if (debug) { printf("Getting coverage for '%s'\n", fn2); }
|
||||
|
||||
if (!*fn2) { continue; }
|
||||
|
||||
if (lstat(fn2, &st) || access(fn2, R_OK)) {
|
||||
|
||||
WARNF("Unable to access '%s'", fn2);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
++done;
|
||||
|
||||
if (!S_ISREG(st.st_mode) || !st.st_size) { continue; }
|
||||
|
||||
if ((fn3 = strrchr(fn2, '/'))) {
|
||||
|
||||
++fn3;
|
||||
|
||||
} else {
|
||||
|
||||
fn3 = fn2;
|
||||
|
||||
}
|
||||
|
||||
if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
|
||||
|
||||
WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
|
||||
stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
|
||||
stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
|
||||
|
||||
}
|
||||
|
||||
if (!collect_coverage) {
|
||||
|
||||
snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3);
|
||||
|
||||
}
|
||||
|
||||
if (read_file(fn2)) {
|
||||
|
||||
if (wait_for_gdb) {
|
||||
|
||||
fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
|
||||
fprintf(stderr, "exec: kill -CONT %d\n", getpid());
|
||||
kill(0, SIGSTOP);
|
||||
|
||||
}
|
||||
|
||||
showmap_run_target_forkserver(fsrv, in_data, in_len);
|
||||
ck_free(in_data);
|
||||
|
||||
if (child_crashed && debug) { WARNF("crashed: %s", fn2); }
|
||||
|
||||
if (collect_coverage)
|
||||
analyze_results(fsrv);
|
||||
else
|
||||
tcnt = write_results_to_file(fsrv, outfile);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return done;
|
||||
|
||||
}
|
||||
|
||||
/* Show banner. */
|
||||
|
||||
static void show_banner(void) {
|
||||
@ -823,6 +1100,7 @@ static void usage(u8 *argv0) {
|
||||
" With -C, -o is a file, without -C it must be a "
|
||||
"directory\n"
|
||||
" and each bitmap will be written there individually.\n"
|
||||
" -I filelist - alternatively to -i, -I is a list of files\n"
|
||||
" -C - collect coverage, writes all edges to -o and gives a "
|
||||
"summary\n"
|
||||
" Must be combined with -i.\n"
|
||||
@ -835,6 +1113,10 @@ static void usage(u8 *argv0) {
|
||||
"This tool displays raw tuple data captured by AFL instrumentation.\n"
|
||||
"For additional help, consult %s/README.md.\n\n"
|
||||
|
||||
"If you use -i/-I mode, then custom mutator post_process send send "
|
||||
"functionality\n"
|
||||
"is supported.\n\n"
|
||||
|
||||
"Environment variables used:\n"
|
||||
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
|
||||
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
|
||||
@ -893,10 +1175,17 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
|
||||
|
||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshVXY")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'V':
|
||||
code_cov = true;
|
||||
collect_coverage = true;
|
||||
quiet_mode = true;
|
||||
setenv("__AFL_CODE_COVERAGE", "1", 1);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
no_classify = true;
|
||||
break;
|
||||
@ -911,6 +1200,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
in_dir = optarg;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
if (in_filelist) { FATAL("Multiple -I options not supported"); }
|
||||
in_filelist = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
|
||||
if (out_file) { FATAL("Multiple -o options not supported"); }
|
||||
@ -1081,7 +1375,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
break;
|
||||
|
||||
case 'Y': // fallthough
|
||||
case 'Y': // fallthrough
|
||||
#ifdef __linux__
|
||||
case 'X': /* NYX mode */
|
||||
|
||||
@ -1133,10 +1427,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (optind == argc || !out_file) { usage(argv[0]); }
|
||||
|
||||
if (in_dir) {
|
||||
if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
|
||||
|
||||
if (in_dir || in_filelist) {
|
||||
|
||||
if (!out_file && !collect_coverage)
|
||||
FATAL("for -i you need to specify either -C and/or -o");
|
||||
FATAL("for -i/-I you need to specify either -C and/or -o");
|
||||
|
||||
}
|
||||
|
||||
@ -1193,7 +1489,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (in_dir) {
|
||||
if (in_dir || in_filelist) {
|
||||
|
||||
/* If we don't have a file name chosen yet, use a safe default. */
|
||||
u8 *use_dir = ".";
|
||||
@ -1213,6 +1509,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
// If @@ are in the target args, replace them and also set use_stdin=false.
|
||||
detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
|
||||
fsrv->out_file = stdin_file;
|
||||
fsrv->out_fd =
|
||||
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", stdin_file); }
|
||||
|
||||
} else {
|
||||
|
||||
// If @@ are in the target args, replace them and also set use_stdin=false.
|
||||
@ -1266,6 +1570,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
afl = calloc(1, sizeof(afl_state_t));
|
||||
|
||||
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
|
||||
|
||||
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
|
||||
@ -1297,7 +1603,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (!fsrv->nyx_mode && in_dir) {
|
||||
if (!fsrv->nyx_mode && (in_dir || in_filelist)) {
|
||||
|
||||
(void)check_binary_signatures(fsrv->target_path);
|
||||
|
||||
@ -1378,28 +1684,66 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
fsrv->map_size = map_size;
|
||||
|
||||
} else {
|
||||
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
(get_afl_env("AFL_DEBUG_CHILD") ||
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
|
||||
? 1
|
||||
: 0);
|
||||
|
||||
}
|
||||
|
||||
if (in_dir) {
|
||||
if (in_dir || in_filelist) {
|
||||
|
||||
afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
|
||||
afl->afl_env.afl_custom_mutator_library =
|
||||
getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
|
||||
afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
|
||||
setup_custom_mutators(afl);
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) {
|
||||
|
||||
WARNF(
|
||||
"Custom mutator environment detected, this is only supported in "
|
||||
"-i/-I mode!\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (in_dir || in_filelist) {
|
||||
|
||||
DIR *dir_in, *dir_out = NULL;
|
||||
u8 *dn = NULL;
|
||||
|
||||
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
if (in_filelist) {
|
||||
|
||||
// if a queue subdirectory exists switch to that
|
||||
u8 *dn = alloc_printf("%s/queue", in_dir);
|
||||
if ((dir_in = opendir(dn)) != NULL) {
|
||||
if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist);
|
||||
|
||||
closedir(dir_in);
|
||||
in_dir = dn;
|
||||
} else {
|
||||
|
||||
} else
|
||||
// if a queue subdirectory exists switch to that
|
||||
dn = alloc_printf("%s/queue", in_dir);
|
||||
|
||||
ck_free(dn);
|
||||
if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
|
||||
if ((dir_in = opendir(dn)) != NULL) {
|
||||
|
||||
closedir(dir_in);
|
||||
in_dir = dn;
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(dn);
|
||||
|
||||
}
|
||||
|
||||
if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
|
||||
|
||||
}
|
||||
|
||||
if (!collect_coverage) {
|
||||
|
||||
@ -1415,18 +1759,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
} else {
|
||||
|
||||
if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
|
||||
if ((coverage_map = (u8 *)malloc((map_size + 64))) == NULL) {
|
||||
|
||||
FATAL("coult not grab memory");
|
||||
|
||||
}
|
||||
|
||||
edges_only = false;
|
||||
raw_instr_output = true;
|
||||
|
||||
}
|
||||
|
||||
atexit(at_exit_handler);
|
||||
fsrv->out_file = stdin_file;
|
||||
fsrv->out_fd =
|
||||
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
|
||||
|
||||
if (get_afl_env("AFL_DEBUG")) {
|
||||
|
||||
@ -1442,20 +1786,26 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
(get_afl_env("AFL_DEBUG_CHILD") ||
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
|
||||
? 1
|
||||
: 0);
|
||||
|
||||
map_size = fsrv->map_size;
|
||||
|
||||
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
|
||||
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
|
||||
|
||||
if (execute_testcases(in_dir) == 0) {
|
||||
if (in_dir) {
|
||||
|
||||
FATAL("could not read input testcases from %s", in_dir);
|
||||
if (execute_testcases(in_dir) == 0) {
|
||||
|
||||
FATAL("could not read input testcases from %s", in_dir);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (execute_testcases_filelist(in_filelist) == 0) {
|
||||
|
||||
FATAL("could not read input testcases from %s", in_filelist);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int fd = 0;
|
||||
int fd = 0, cnt;
|
||||
char buff[8];
|
||||
char *buf = buff;
|
||||
|
||||
@ -32,7 +32,6 @@ int main(int argc, char **argv) {
|
||||
if (argc == 2) {
|
||||
|
||||
buf = argv[1];
|
||||
printf("Input %s - ", buf);
|
||||
|
||||
} else {
|
||||
|
||||
@ -47,15 +46,19 @@ int main(int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
if (read(fd, buf, sizeof(buf)) < 1) {
|
||||
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
|
||||
|
||||
printf("Hum?\n");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
buf[cnt] = 0;
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf);
|
||||
|
||||
// we support three input cases (plus a 4th if stdin is used but there is no
|
||||
// input)
|
||||
switch (buf[0]) {
|
||||
|
@ -28,7 +28,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
|
||||
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 12 && {
|
||||
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 22 && {
|
||||
$ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine"
|
||||
} || {
|
||||
$ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES"
|
||||
@ -152,7 +152,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
|
||||
}
|
||||
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 12 && {
|
||||
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"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user