Merge branch 'dev' of github.com:AFLplusplus/AFLplusplus into dev

This commit is contained in:
Andrea Fioraldi 2020-12-08 22:43:05 +01:00
commit ad29eef271
149 changed files with 1871 additions and 779 deletions

View File

@ -29,7 +29,7 @@ CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
if CLANG_FORMAT_BIN is None: if CLANG_FORMAT_BIN is None:
o = 0 o = 0
try: try:
p = subprocess.Popen(["clang-format-10", "--version"], stdout=subprocess.PIPE) p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
o, _ = p.communicate() o, _ = p.communicate()
o = str(o, "utf-8") o = str(o, "utf-8")
o = re.sub(r".*ersion ", "", o) o = re.sub(r".*ersion ", "", o)
@ -37,7 +37,7 @@ if CLANG_FORMAT_BIN is None:
o = o[:o.find(".")] o = o[:o.find(".")]
o = int(o) o = int(o)
except: except:
print ("clang-format-10 is needed. Aborted.") print ("clang-format-11 is needed. Aborted.")
exit(1) exit(1)
#if o < 7: #if o < 7:
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0: # if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
@ -46,13 +46,13 @@ if CLANG_FORMAT_BIN is None:
# CLANG_FORMAT_BIN = 'clang-format-8' # CLANG_FORMAT_BIN = 'clang-format-8'
# elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0: # elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-9' # CLANG_FORMAT_BIN = 'clang-format-9'
# elif subprocess.call(['which', 'clang-format-10'], stdout=subprocess.PIPE) == 0: # elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-10' # CLANG_FORMAT_BIN = 'clang-format-11'
# else: # else:
# print ("clang-format 7 or above is needed. Aborted.") # print ("clang-format 7 or above is needed. Aborted.")
# exit(1) # exit(1)
else: else:
CLANG_FORMAT_BIN = 'clang-format-10' CLANG_FORMAT_BIN = 'clang-format-11'
COLUMN_LIMIT = 80 COLUMN_LIMIT = 80
for line in fmt.split("\n"): for line in fmt.split("\n"):

1
.gitignore vendored
View File

@ -8,6 +8,7 @@
*.pyc *.pyc
*.dSYM *.dSYM
as as
a.out
ld ld
in in
out out

5
.gitmodules vendored
View File

@ -1,9 +1,8 @@
[submodule "unicorn_mode/unicornafl"] [submodule "unicorn_mode/unicornafl"]
path = unicorn_mode/unicornafl path = unicorn_mode/unicornafl
url = https://github.com/AFLplusplus/unicornafl url = https://github.com/AFLplusplus/unicornafl
[submodule "custom_mutators/grammar_mutator"]
[submodule "custom_mutators/Grammar-Mutator"] path = custom_mutators/grammar_mutator/grammar_mutator
path = custom_mutators/Grammar-Mutator
url = https://github.com/AFLplusplus/Grammar-Mutator url = https://github.com/AFLplusplus/Grammar-Mutator
[submodule "qemu_mode/qemuafl"] [submodule "qemu_mode/qemuafl"]
path = qemu_mode/qemuafl path = qemu_mode/qemuafl

View File

@ -16,9 +16,9 @@ project, or added a file in a directory we already format, otherwise run:
``` ```
Regarding the coding style, please follow the AFL style. Regarding the coding style, please follow the AFL style.
No camel case at all and use the AFL's macros wherever possible No camel case at all and use AFL's macros wherever possible
(e.g. WARNF, FATAL, MAP_SIZE, ...). (e.g. WARNF, FATAL, MAP_SIZE, ...).
Remember that AFLplusplus has to build and run on many platforms, so Remember that AFLplusplus has to build and run on many platforms, so
generalize your Makefiles/GNUmakefile (or your patches to our pre-existing generalize your Makefiles/GNUmakefile (or your patches to our pre-existing
Makefiles) to be as much generic as possible. Makefiles) to be as generic as possible.

View File

@ -85,7 +85,9 @@ ifneq "$(shell uname)" "Darwin"
endif endif
endif endif
# OS X does not like _FORTIFY_SOURCE=2 # OS X does not like _FORTIFY_SOURCE=2
CFLAGS_OPT += -D_FORTIFY_SOURCE=2 ifndef DEBUG
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
endif
endif endif
ifeq "$(shell uname)" "SunOS" ifeq "$(shell uname)" "SunOS"
@ -232,7 +234,9 @@ else
endif endif
ifneq "$(filter Linux GNU%,$(shell uname))" "" ifneq "$(filter Linux GNU%,$(shell uname))" ""
ifndef DEBUG
override CFLAGS += -D_FORTIFY_SOURCE=2 override CFLAGS += -D_FORTIFY_SOURCE=2
endif
LDFLAGS += -ldl -lrt -lm LDFLAGS += -ldl -lrt -lm
endif endif
@ -417,7 +421,7 @@ src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86 afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86 afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
@ -496,8 +500,8 @@ code-format:
./.custom-format.py -i instrumentation/*.c ./.custom-format.py -i instrumentation/*.c
@#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
./.custom-format.py -i examples/*/*.c* ./.custom-format.py -i utils/*/*.c*
./.custom-format.py -i examples/*/*.h ./.custom-format.py -i utils/*/*.h
./.custom-format.py -i test/*.c ./.custom-format.py -i test/*.c
./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c
./.custom-format.py -i qemu_mode/libcompcov/*.cc ./.custom-format.py -i qemu_mode/libcompcov/*.cc
@ -512,7 +516,7 @@ code-format:
ifndef AFL_NO_X86 ifndef AFL_NO_X86
test_build: afl-cc afl-as afl-showmap test_build: afl-cc afl-as afl-showmap
@echo "[*] Testing the CC wrapper and instrumentation output..." @echo "[*] Testing the CC wrapper and instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr @rm -f test-instr
@ -538,14 +542,14 @@ all_done: test_build
.PHONY: clean .PHONY: clean
clean: clean:
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ test/unittests/unit_hash test/unittests/unit_rand rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand
-$(MAKE) -f GNUmakefile.llvm clean -$(MAKE) -f GNUmakefile.llvm clean
-$(MAKE) -f GNUmakefile.gcc_plugin clean -$(MAKE) -f GNUmakefile.gcc_plugin clean
$(MAKE) -C libdislocator clean $(MAKE) -C libdislocator clean
$(MAKE) -C libtokencap clean $(MAKE) -C libtokencap clean
$(MAKE) -C examples/afl_network_proxy clean $(MAKE) -C utils/afl_network_proxy clean
$(MAKE) -C examples/socket_fuzzing clean $(MAKE) -C utils/socket_fuzzing clean
$(MAKE) -C examples/argv_fuzzing clean $(MAKE) -C utils/argv_fuzzing clean
$(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/unsigaction clean
$(MAKE) -C qemu_mode/libcompcov clean $(MAKE) -C qemu_mode/libcompcov clean
ifeq "$(IN_REPO)" "1" ifeq "$(IN_REPO)" "1"
@ -568,10 +572,10 @@ distrib: all
-$(MAKE) -f GNUmakefile.gcc_plugin -$(MAKE) -f GNUmakefile.gcc_plugin
$(MAKE) -C libdislocator $(MAKE) -C libdislocator
$(MAKE) -C libtokencap $(MAKE) -C libtokencap
$(MAKE) -C examples/aflpp_driver $(MAKE) -C utils/aflpp_driver
$(MAKE) -C examples/afl_network_proxy $(MAKE) -C utils/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing $(MAKE) -C utils/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing $(MAKE) -C utils/argv_fuzzing
-cd qemu_mode && sh ./build_qemu_support.sh -cd qemu_mode && sh ./build_qemu_support.sh
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
@ -579,9 +583,9 @@ distrib: all
binary-only: all binary-only: all
$(MAKE) -C libdislocator $(MAKE) -C libdislocator
$(MAKE) -C libtokencap $(MAKE) -C libtokencap
$(MAKE) -C examples/afl_network_proxy $(MAKE) -C utils/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing $(MAKE) -C utils/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing $(MAKE) -C utils/argv_fuzzing
-cd qemu_mode && sh ./build_qemu_support.sh -cd qemu_mode && sh ./build_qemu_support.sh
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
@ -591,7 +595,7 @@ source-only: all
-$(MAKE) -f GNUmakefile.gcc_plugin -$(MAKE) -f GNUmakefile.gcc_plugin
$(MAKE) -C libdislocator $(MAKE) -C libdislocator
$(MAKE) -C libtokencap $(MAKE) -C libtokencap
$(MAKE) -C examples/aflpp_driver $(MAKE) -C utils/aflpp_driver
%.8: % %.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@ -624,15 +628,17 @@ install: all $(MANPAGES)
@if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
@if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
@if [ -f examples/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 examples/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
@if [ -f examples/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 examples/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
-$(MAKE) -f GNUmakefile.llvm install -$(MAKE) -f GNUmakefile.llvm install
-$(MAKE) -f GNUmakefile.gcc_plugin install -$(MAKE) -f GNUmakefile.gcc_plugin install
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++ ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH) @mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
install -m0644 *.8 ${DESTDIR}$(MAN_PATH) install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH) install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)

View File

@ -19,7 +19,7 @@
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
#TEST_MMAP=1
PREFIX ?= /usr/local PREFIX ?= /usr/local
HELPER_PATH ?= $(PREFIX)/lib/afl HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin BIN_PATH ?= $(PREFIX)/bin

View File

@ -34,7 +34,7 @@ ifeq "$(shell uname)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
ifeq "$(HAS_OPT)" "1" ifeq "$(HAS_OPT)" "1"
$(warn llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") $(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
endif endif
else else
LLVM_CONFIG ?= llvm-config LLVM_CONFIG ?= llvm-config
@ -361,6 +361,8 @@ instrumentation/afl-common.o: ./src/afl-common.c
@ln -sf afl-cc ./afl-c++ @ln -sf afl-cc ./afl-c++
@ln -sf afl-cc ./afl-gcc @ln -sf afl-cc ./afl-gcc
@ln -sf afl-cc ./afl-g++ @ln -sf afl-cc ./afl-g++
@ln -sf afl-cc ./afl-clang
@ln -sf afl-cc ./afl-clang++
@ln -sf afl-cc ./afl-clang-fast @ln -sf afl-cc ./afl-clang-fast
@ln -sf afl-cc ./afl-clang-fast++ @ln -sf afl-cc ./afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" "" ifneq "$(AFL_CLANG_FLTO)" ""

View File

@ -22,8 +22,8 @@
afl++ is a superior fork to Google's afl - more speed, more and better afl++ is a superior fork to Google's afl - more speed, more and better
mutations, more and better instrumentation, custom module support, etc. mutations, more and better instrumentation, custom module support, etc.
If you want to use afl++ for you academic work, check the [papers page](https://aflplus.plus/papers/) If you want to use afl++ for your academic work, check the [papers page](https://aflplus.plus/papers/)
in the website. on the website.
## Major changes in afl++ 3.0 ## Major changes in afl++ 3.0
@ -55,6 +55,7 @@ behaviours and defaults:
* a caching of testcases can now be performed and can be modified by * a caching of testcases can now be performed and can be modified by
editing config.h for TESTCASE_CACHE or by specifying the env variable editing config.h for TESTCASE_CACHE or by specifying the env variable
`AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500 (default: 50). `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500 (default: 50).
* examples/ got renamed to utils/
## Contents ## Contents
@ -273,7 +274,7 @@ anything below 9 is not recommended.
v v
+---------------------------------+ +---------------------------------+
| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) | clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
+---------------------------------+ see [instrumentation/README.md](instrumentation/README.md) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md)
| |
| if not, or if the target fails with LLVM afl-clang-fast/++ | if not, or if the target fails with LLVM afl-clang-fast/++
| |
@ -292,7 +293,7 @@ anything below 9 is not recommended.
Clickable README links for the chosen compiler: Clickable README links for the chosen compiler:
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md) * [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
* [LLVM mode - afl-clang-fast](instrumentation/README.md) * [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md) * [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
* GCC mode (afl-gcc) has no README as it has no own features * GCC mode (afl-gcc) has no README as it has no own features
@ -525,7 +526,7 @@ as test data in there.
If you do not want anything special, the defaults are already usually best, If you do not want anything special, the defaults are already usually best,
hence all you need is to specify the seed input directory with the result of hence all you need is to specify the seed input directory with the result of
step [2. Collect inputs](#a)a-collect-inputs)): step [2a. Collect inputs](#a-collect-inputs):
`afl-fuzz -i input -o output -- bin/target -d @@` `afl-fuzz -i input -o output -- bin/target -d @@`
Note that the directory specified with -o will be created if it does not exist. Note that the directory specified with -o will be created if it does not exist.
@ -541,7 +542,7 @@ that it could not connect to the forkserver), then you can increase this
with the `-m` option, the value is in MB. To disable any memory limits with the `-m` option, the value is in MB. To disable any memory limits
(beware!) set `-m none` - which is usually required for ASAN compiled targets. (beware!) set `-m none` - which is usually required for ASAN compiled targets.
Adding a dictionary is helpful. See the [dictionaries/](dictionaries/) if Adding a dictionary is helpful. See the directory [dictionaries/](dictionaries/) if
something is already included for your data format, and tell afl-fuzz to load something is already included for your data format, and tell afl-fuzz to load
that dictionary by adding `-x dictionaries/FORMAT.dict`. With afl-clang-lto that dictionary by adding `-x dictionaries/FORMAT.dict`. With afl-clang-lto
you have an autodictionary generation for which you need to do nothing except you have an autodictionary generation for which you need to do nothing except
@ -760,10 +761,10 @@ cd unicorn_mode
If the goal is to fuzz a dynamic library then there are two options available. If the goal is to fuzz a dynamic library then there are two options available.
For both you need to write a small hardness that loads and calls the library. For both you need to write a small hardness that loads and calls the library.
Faster is the frida solution: [examples/afl_frida/README.md](examples/afl_frida/README.md) Faster is the frida solution: [utils/afl_frida/README.md](utils/afl_frida/README.md)
Another, less precise and slower option is using ptrace with debugger interrupt Another, less precise and slower option is using ptrace with debugger interrupt
instrumentation: [examples/afl_untracer/README.md](examples/afl_untracer/README.md) instrumentation: [utils/afl_untracer/README.md](utils/afl_untracer/README.md)
### More ### More
@ -1037,7 +1038,7 @@ Here are some of the most important caveats for AFL:
wholly wrap the actual data format to be tested. wholly wrap the actual data format to be tested.
To work around this, you can comment out the relevant checks (see To work around this, you can comment out the relevant checks (see
examples/libpng_no_checksum/ for inspiration); if this is not possible, utils/libpng_no_checksum/ for inspiration); if this is not possible,
you can also write a postprocessor, one of the hooks of custom mutators. you can also write a postprocessor, one of the hooks of custom mutators.
See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use
`AFL_CUSTOM_MUTATOR_LIBRARY` `AFL_CUSTOM_MUTATOR_LIBRARY`
@ -1109,7 +1110,8 @@ without feedback, bug reports, or patches from:
Andrea Biondo Vincent Le Garrec Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu Khaled Yakdan Kuang-che Wu
Josephine Calliotte Konrad Welc Josephine Calliotte Konrad Welc
David Carlier Ruben ten Hove Thomas Rooijakkers David Carlier
Ruben ten Hove
``` ```
Thank you! Thank you!

View File

@ -113,14 +113,15 @@ function usage() {
" -C - keep crashing inputs, reject everything else\n" \ " -C - keep crashing inputs, reject everything else\n" \
" -e - solve for edge coverage only, ignore hit counts\n" \ " -e - solve for edge coverage only, ignore hit counts\n" \
"\n" \ "\n" \
"For additional tips, please consult docs/README.md\n" \ "For additional tips, please consult README.md\n" \
"\n" \ "\n" \
"Environment variables used:\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 target to come up, initially\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \ "AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
"AFL_PATH: path for the afl-showmap binary\n" \ "AFL_PATH: path for the afl-showmap binary\n" \
"AFL_SKIP_BIN_CHECK: skip check for target binary\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n"
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n"
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n"
exit 1 exit 1
} }

View File

@ -128,7 +128,7 @@ Minimization settings:
-C - keep crashing inputs, reject everything else -C - keep crashing inputs, reject everything else
-e - solve for edge coverage only, ignore hit counts -e - solve for edge coverage only, ignore hit counts
For additional tips, please consult docs/README.md. For additional tips, please consult README.md.
Environment variables used: Environment variables used:
AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory

View File

@ -7,15 +7,13 @@ For further information and documentation on how to write your own, read [the do
If you use git to clone afl++, then the following will incorporate our If you use git to clone afl++, then the following will incorporate our
excellent grammar custom mutator: excellent grammar custom mutator:
``` ```sh
git submodule init git submodule update --init
git submodule update
``` ```
otherwise just use the script: `grammar_mutator/build_grammar_mutator.sh` Read the README in the [Grammar-Mutator] repository on how to use it.
Read the [Grammar-Mutator/README.md](Grammar-Mutator/README.md) on how to use [Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
it.
## Production-Ready Custom Mutators ## Production-Ready Custom Mutators

View File

@ -0,0 +1 @@
b3c4fcf

View File

@ -1,17 +1,140 @@
#!/bin/sh #!/bin/sh
#
# american fuzzy lop++ - unicorn mode build script
# ------------------------------------------------
#
# Originally written by Nathan Voss <njvoss99@gmail.com>
#
# Adapted from code by Andrew Griffiths <agriffiths@google.com> and
# Michal Zalewski
#
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# CompareCoverage and NeverZero counters by Andrea Fioraldi
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# This script downloads, patches, and builds a version of Unicorn with
# minor tweaks to allow Unicorn-emulated binaries to be run under
# afl-fuzz.
#
# The modifications reside in patches/*. The standalone Unicorn library
# will be written to /usr/lib/libunicornafl.so, and the Python bindings
# will be installed system-wide.
#
# You must make sure that Unicorn Engine is not already installed before
# running this script. If it is, please uninstall it first.
test -d Grammar-Mutator || git clone --depth=1 https://github.com/AFLplusplus/Grammar-Mutator GRAMMAR_VERSION="$(cat ./GRAMMAR_VERSION)"
GRAMMAR_REPO="https://github.com/AFLplusplus/grammar-mutator"
cd Grammar-Mutator || exit 1 echo "================================================="
git stash ; git pull echo "Grammar Mutator build script"
echo "================================================="
echo
echo "[*] Performing basic sanity checks..."
PLT=`uname -s`
if [ ! -f "../../config.h" ]; then
echo "[-] Error: key files not found - wrong working directory?"
exit 1
fi
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar
if [ "$PLT" = "Darwin" ]; then
CORES=`sysctl -n hw.ncpu`
TARCMD=tar
fi
if [ "$PLT" = "FreeBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
PREREQ_NOTFOUND=
for i in git $MAKECMD $TARCMD; do
T=`command -v "$i" 2>/dev/null`
if [ "$T" = "" ]; then
echo "[-] Error: '$i' not found. Run 'sudo apt-get install $i' or similar."
PREREQ_NOTFOUND=1
fi
done
if echo "$CC" | grep -qF /afl-; then
echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
PREREQ_NOTFOUND=1
fi
if [ "$PREREQ_NOTFOUND" = "1" ]; then
exit 1
fi
echo "[+] All checks passed!"
echo "[*] Making sure grammar mutator is checked out"
git status 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then
echo "[*] initializing grammar mutator submodule"
git submodule init || exit 1
git submodule update ./grammar-mutator 2>/dev/null # ignore errors
else
echo "[*] cloning grammar mutator"
test -d grammar-mutator || {
CNT=1
while [ '!' -d grammar-mutator -a "$CNT" -lt 4 ]; do
echo "Trying to clone grammar-mutator (attempt $CNT/3)"
git clone "$GRAMMAR_REPO"
CNT=`expr "$CNT" + 1`
done
}
fi
test -d grammar-mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
echo "[+] Got grammar mutator."
cd "grammar-mutator" || exit 1
echo "[*] Checking out $GRAMMAR_VERSION"
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
git checkout "$GRAMMAR_VERSION" || exit 1
echo "[*] Downloading antlr..."
wget -c https://www.antlr.org/download/antlr-4.8-complete.jar wget -c https://www.antlr.org/download/antlr-4.8-complete.jar
cd ..
echo echo
echo echo
echo "All successfully prepared!" echo "[+] All successfully prepared!"
echo "To build for your grammar just do:" echo "[!] To build for your grammar just do:"
echo " cd Grammar_Mutator" echo " cd grammar-mutator"
echo " make GRAMMAR_FILE=/path/to/your/grammar" echo " make GRAMMAR_FILE=/path/to/your/grammar"
echo "You will find a JSON and RUBY grammar in Grammar_Mutator/grammars to play with." echo "[+] You will find a JSON and RUBY grammar in grammar-mutator/grammars to play with."
echo echo

@ -0,0 +1 @@
Subproject commit b3c4fcfa6ae28918bc410f7747135eafd4fb7263

View File

@ -0,0 +1,50 @@
#!/bin/sh
##################################################
# AFL++ tool to update a git ref.
# Usage: ./<script>.sh <new commit hash>
# If no commit hash was provided, it'll take HEAD.
##################################################
TOOL="grammar mutator"
VERSION_FILE='./GRAMMAR_VERSION'
REPO_FOLDER='./grammar_mutator'
THIS_SCRIPT=`basename $0`
BRANCH="stable"
NEW_VERSION="$1"
if [ "$NEW_VERSION" = "-h" ]; then
echo "Internal script to update bound $TOOL version."
echo
echo "Usage: $THIS_SCRIPT <new commit hash>"
echo "If no commit hash is provided, will use HEAD."
echo "-h to show this help screen."
exit 1
fi
git submodule init && git submodule update ./grammar_mutator || exit 1
cd "$REPO_FOLDER" || exit 1
git fetch origin $BRANCH 1>/dev/null || exit 1
git stash 1>/dev/null 2>/dev/null
git stash drop 1>/dev/null 2>/dev/null
git checkout $BRANCH
if [ -z "$NEW_VERSION" ]; then
# No version provided, take HEAD.
NEW_VERSION=$(git rev-parse --short HEAD)
fi
if [ -z "$NEW_VERSION" ]; then
echo "Error getting version."
exit 1
fi
git checkout "$NEW_VERSION" || exit 1
cd ..
rm "$VERSION_FILE"
echo "$NEW_VERSION" > "$VERSION_FILE"
echo "Done. New $TOOL version is $NEW_VERSION."

View File

@ -1,7 +1,10 @@
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "config.h" #include "config.h"
#include "debug.h" #include "debug.h"
#include "afl-fuzz.h" #include "afl-fuzz.h"
@ -21,6 +24,7 @@ typedef struct my_mutator {
afl_state_t *afl; afl_state_t *afl;
u8 * mutator_buf; u8 * mutator_buf;
u8 * out_dir; u8 * out_dir;
u8 * tmp_dir;
u8 * target; u8 * target;
uint32_t seed; uint32_t seed;
@ -55,10 +59,11 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
if (!(data->out_dir = getenv("SYMCC_OUTPUT_DIR"))) { if (!(data->out_dir = getenv("SYMCC_OUTPUT_DIR"))) {
data->out_dir = alloc_printf("%s/symcc", afl->out_dir); data->out_dir = alloc_printf("%s/symcc", afl->out_dir);
setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
} }
data->tmp_dir = alloc_printf("%s/tmp", data->out_dir);
setenv("SYMCC_OUTPUT_DIR", data->tmp_dir, 1);
int pid = fork(); int pid = fork();
if (pid == -1) return NULL; if (pid == -1) return NULL;
@ -84,6 +89,10 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
if (mkdir(data->out_dir, 0755)) if (mkdir(data->out_dir, 0755))
PFATAL("Could not create directory %s", data->out_dir); PFATAL("Could not create directory %s", data->out_dir);
if (mkdir(data->tmp_dir, 0755))
PFATAL("Could not create directory %s", data->tmp_dir);
DBG("out_dir=%s, target=%s\n", data->out_dir, data->target); DBG("out_dir=%s, target=%s\n", data->out_dir, data->target);
return data; return data;
@ -96,33 +105,119 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
const uint8_t *filename_new_queue, const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) { const uint8_t *filename_orig_queue) {
int pipefd[2];
struct stat st;
ACTF("Queueing to symcc: %s", filename_new_queue);
u8 *fn = alloc_printf("%s", filename_new_queue);
if (!(stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size)) {
ck_free(fn);
PFATAL("Couldn't find enqueued file: %s", fn);
}
if (afl_struct->fsrv.use_stdin) {
if (pipe(pipefd) == -1) {
ck_free(fn);
PFATAL("Couldn't create a pipe for interacting with symcc child process");
}
}
int pid = fork(); int pid = fork();
if (pid == -1) return; if (pid == -1) return;
if (pid) pid = waitpid(pid, NULL, 0); if (pid) {
if (pid == 0) {
setenv("SYMCC_INPUT_FILE", afl_struct->fsrv.out_file, 1);
if (afl_struct->fsrv.use_stdin) { if (afl_struct->fsrv.use_stdin) {
u8 *fn = alloc_printf("%s/%s", afl_struct->out_dir, filename_new_queue); close(pipefd[0]);
int fd = open(fn, O_RDONLY); int fd = open(fn, O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
ssize_t r = read(fd, data->mutator_buf, MAX_FILE); ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
close(fd);
DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r); DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r);
if (r <= 0) return;
close(0);
ck_write(0, data->mutator_buf, r, fn);
ck_free(fn); ck_free(fn);
close(fd);
if (r <= 0) {
close(pipefd[1]);
return;
}
if (r > fcntl(pipefd[1], F_GETPIPE_SZ))
fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
ck_write(pipefd[1], data->mutator_buf, r, filename_new_queue);
} else {
ck_free(fn);
close(pipefd[1]);
PFATAL(
"Something happened to the enqueued file before sending its "
"contents to symcc binary");
} }
close(pipefd[1]);
}
pid = waitpid(pid, NULL, 0);
// At this point we need to transfer files to output dir, since their names
// collide and symcc will just overwrite them
struct dirent **nl;
int32_t items = scandir(data->tmp_dir, &nl, NULL, NULL);
u8 * origin_name = basename(filename_new_queue);
int32_t i;
if (items > 0) {
for (i = 0; i < (u32)items; ++i) {
struct stat st;
u8 *source_name = alloc_printf("%s/%s", data->tmp_dir, nl[i]->d_name);
DBG("test=%s\n", fn);
if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
u8 *destination_name =
alloc_printf("%s/%s.%s", data->out_dir, origin_name, nl[i]->d_name);
rename(source_name, destination_name);
ck_free(destination_name);
DBG("found=%s\n", source_name);
}
ck_free(source_name);
free(nl[i]);
}
free(nl);
}
}
if (pid == 0) {
if (afl_struct->fsrv.use_stdin) {
unsetenv("SYMCC_INPUT_FILE");
close(pipefd[1]);
dup2(pipefd[0], 0);
} else {
setenv("SYMCC_INPUT_FILE", afl_struct->fsrv.out_file, 1);
} }
DBG("exec=%s\n", data->target); DBG("exec=%s\n", data->target);
@ -130,6 +225,7 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
close(2); close(2);
dup2(afl_struct->fsrv.dev_null_fd, 1); dup2(afl_struct->fsrv.dev_null_fd, 1);
dup2(afl_struct->fsrv.dev_null_fd, 2); dup2(afl_struct->fsrv.dev_null_fd, 2);
execvp(data->target, afl_struct->argv); execvp(data->target, afl_struct->argv);
DBG("exec=FAIL\n"); DBG("exec=FAIL\n");
exit(-1); exit(-1);
@ -180,7 +276,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
struct dirent **nl; struct dirent **nl;
int32_t i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL); int32_t i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL);
size_t size = 0; ssize_t size = 0;
if (items <= 0) return 0; if (items <= 0) return 0;
@ -199,6 +295,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
size = read(fd, data->mutator_buf, max_size); size = read(fd, data->mutator_buf, max_size);
*out_buf = data->mutator_buf; *out_buf = data->mutator_buf;
close(fd); close(fd);
done = 1; done = 1;
@ -217,7 +314,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
free(nl); free(nl);
DBG("FUZZ size=%lu\n", size); DBG("FUZZ size=%lu\n", size);
return size; return (uint32_t)size;
} }

View File

@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char **argv) {
if (argc < 2) {
printf("Need a file argument\n");
return 1;
}
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
printf("Couldn't open file\n");
return 1;
}
uint32_t value = 0;
read(fd, &value, sizeof(value));
close(fd);
value = value ^ 0xffffffff;
if (value == 0x11223344) printf("Value one\n");
if (value == 0x44332211) printf("Value two\n");
if (value != 0x0) printf("Not zero\n");
return 0;
}

View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
char input_buffer[16];
uint32_t comparisonValue;
size_t bytesRead;
bytesRead = read(STDIN_FILENO, input_buffer, sizeof(input_buffer));
if (bytesRead < 0) exit(-1);
comparisonValue = *(uint32_t *)input_buffer;
comparisonValue = comparisonValue ^ 0xff112233;
if (comparisonValue == 0x66554493) {
printf("First value\n");
} else {
if (comparisonValue == 0x84444415) printf("Second value\n");
}
return 0;
}

View File

@ -1,6 +1,6 @@
# AFL dictionaries # AFL dictionaries
(See [../docs/README.md](../docs/README.md) for the general instruction manual.) (See [../README.md](../README.md) for the general instruction manual.)
This subdirectory contains a set of dictionaries that can be used in This subdirectory contains a set of dictionaries that can be used in
conjunction with the -x option to allow the fuzzer to effortlessly explore the conjunction with the -x option to allow the fuzzer to effortlessly explore the

View File

@ -11,6 +11,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++3.00a (develop) ### Version ++3.00a (develop)
- llvm_mode/ and gcc_plugin/ moved to instrumentation/ - llvm_mode/ and gcc_plugin/ moved to instrumentation/
- examples/ renamed to utils/
- all compilers combined to afl-cc which emulates the previous ones - all compilers combined to afl-cc which emulates the previous ones
- afl-llvm/gcc-rt.o merged into afl-compiler-rt.o - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o
- afl-fuzz - afl-fuzz
@ -21,40 +22,50 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
a schedule performance score, which is much better that the previous a schedule performance score, which is much better that the previous
walk the whole queue approach. Select the old mode with -Z (auto enabled walk the whole queue approach. Select the old mode with -Z (auto enabled
with -M) with -M)
- rpc.statsd support by Edznux, thanks a lot! - rpc.statsd support, for stats and charts, by Edznux, thanks a lot!
- Marcel Boehme submitted a patch that improves all AFFast schedules :) - Marcel Boehme submitted a patch that improves all AFFast schedules :)
- not specifying -M or -S will now auto-set "-S default" - not specifying -M or -S will now auto-set "-S default"
- reading testcases from -i now descends into subdirectories - reading testcases from -i now descends into subdirectories
- allow up to 4 times the -x command line option - allow the -x command line option up to 4 times
- loaded extras now have a duplicate protection - loaded extras now have a duplication protection
- If test cases are too large we do a partial read on the maximum - If test cases are too large we do a partial read on the maximum
supported size supported size
- longer seeds with the same trace information will now be ignored - longer seeds with the same trace information will now be ignored
for fuzzing but still be used for splicing for fuzzing but still be used for splicing
- crashing seeds are now not prohibiting a run anymore but are - crashing seeds are now not prohibiting a run anymore but are
skipped. They are used for splicing though. skipped - they are used for splicing, though
- update MOpt for expanded havoc modes - update MOpt for expanded havoc modes
- setting the env var AFL_NO_AUTODICT will not load an LTO autodictionary
- added NO_SPLICING compile option and makefile define - added NO_SPLICING compile option and makefile define
- added INTROSPECTION make target that writes all mutations to - added INTROSPECTION make target that writes all mutations to
out/NAME/introspection.txt out/NAME/introspection.txt
- added INTROSPECTION support for custom modules
- print special compile time options used in help output - print special compile time options used in help output
- when using -c cmplog, one of the childs was not killed, fixed
- somewhere we broke -n dumb fuzzing, fixed
- added afl_custom_describe to the custom mutator API to allow for easy
mutation reproduction on crashing inputs
- instrumentation - instrumentation
- We received an enhanced gcc_plugin module from AdaCore, thank you - We received an enhanced gcc_plugin module from AdaCore, thank you
very much!! very much!!
- not overriding -Ox or -fno-unroll-loops anymore - not overriding -Ox or -fno-unroll-loops anymore
- we now have our own trace-pc-guard implementation. It is the same as - we now have our own trace-pc-guard implementation. It is the same as
-fsanitize-coverage=trace-pc-guard from llvm 12, but: it is a) inline -fsanitize-coverage=trace-pc-guard from llvm 12, but: it is a) inline
and b) works from llvm 10+ on :) and b) works from llvm 10.0.1 + onwards :)
- new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz - new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz
-x dictionary of string comparisons found during compilation -x dictionary of string comparisons found during compilation
- LTO autodict now also collects interesting cmp comparisons, - LTO autodict now also collects interesting cmp comparisons,
std::string compare + find + ==, bcmp std::string compare + find + ==, bcmp
- fix crash in dict2file for integers > 64 bit - fix crash in dict2file for integers > 64 bit
- unicornafl synced with upstream (arm64 fix, better rust bindings) - custom mutators
- added a new custom mutator: symcc -> https://github.com/eurecom-s3/symcc/ - added a new custom mutator: symcc -> https://github.com/eurecom-s3/symcc/
- added a new custom mutator: libfuzzer that integrates libfuzzer mutations - added a new custom mutator: libfuzzer that integrates libfuzzer mutations
- Our afl++ Grammar-Mutator is now better integrated into custom_mutators/ - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/
- added INTROSPECTION support for custom modules
- python fuzz function was not optional, fixed
- some python mutator speed improvements
- unicornafl synced with upstream version 1.02 (fixes, better rust bindings)
- renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD
- added AFL_CRASH_EXITCODE env variable to treat a child exitcode as crash
### Version ++2.68c (release) ### Version ++2.68c (release)

View File

@ -63,7 +63,7 @@ x10 - that is a x100 difference!).
If modifying the source is not an option (e.g. because you only have a binary If modifying the source is not an option (e.g. because you only have a binary
and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD
to emulate the network. This is also much faster than the real network would be. to emulate the network. This is also much faster than the real network would be.
See [examples/socket_fuzzing/](../examples/socket_fuzzing/). See [utils/socket_fuzzing/](../utils/socket_fuzzing/).
There is an outdated afl++ branch that implements networking if you are There is an outdated afl++ branch that implements networking if you are
desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) -

View File

@ -1 +0,0 @@
../README.md

View File

@ -15,7 +15,7 @@
high enough. Otherwise try retrowrite, afl-dyninst and if these high enough. Otherwise try retrowrite, afl-dyninst and if these
fail too then try standard qemu_mode with AFL_ENTRYPOINT to where you need it. fail too then try standard qemu_mode with AFL_ENTRYPOINT to where you need it.
If your target is a library use examples/afl_frida/. If your target is a library use utils/afl_frida/.
If your target is non-linux then use unicorn_mode/. If your target is non-linux then use unicorn_mode/.
@ -65,14 +65,14 @@
## AFL FRIDA ## AFL FRIDA
If you want to fuzz a binary-only shared library then you can fuzz it with If you want to fuzz a binary-only shared library then you can fuzz it with
frida-gum via examples/afl_frida/, you will have to write a harness to frida-gum via utils/afl_frida/, you will have to write a harness to
call the target function in the library, use afl-frida.c as a template. call the target function in the library, use afl-frida.c as a template.
## AFL UNTRACER ## AFL UNTRACER
If you want to fuzz a binary-only shared library then you can fuzz it with If you want to fuzz a binary-only shared library then you can fuzz it with
examples/afl_untracer/, use afl-untracer.c as a template. utils/afl_untracer/, use afl-untracer.c as a template.
It is slower than AFL FRIDA (see above). It is slower than AFL FRIDA (see above).

View File

@ -34,6 +34,7 @@ C/C++:
void *afl_custom_init(afl_state_t *afl, unsigned int seed); void *afl_custom_init(afl_state_t *afl, unsigned int seed);
unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size); unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size); size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);
const char *afl_custom_describe(void *data, size_t max_description_len);
size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf); size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);
int afl_custom_init_trim(void *data, unsigned char *buf, size_t buf_size); int afl_custom_init_trim(void *data, unsigned char *buf, size_t buf_size);
size_t afl_custom_trim(void *data, unsigned char **out_buf); size_t afl_custom_trim(void *data, unsigned char **out_buf);
@ -57,6 +58,9 @@ def fuzz_count(buf, add_buf, max_size):
def fuzz(buf, add_buf, max_size): def fuzz(buf, add_buf, max_size):
return mutated_out return mutated_out
def describe(max_description_length):
return "description_of_current_mutation"
def post_process(buf): def post_process(buf):
return out_buf return out_buf
@ -102,7 +106,7 @@ def introspection():
of fuzzing attempts with this input based on a few factors. of fuzzing attempts with this input based on a few factors.
If however the custom mutator wants to set this number instead on how often If however the custom mutator wants to set this number instead on how often
it is called for a specific queue entry, use this function. it is called for a specific queue entry, use this function.
This function in mostly useful if **not** `AFL_CUSTOM_MUTATOR_ONLY` is used. This function is most useful if `AFL_CUSTOM_MUTATOR_ONLY` is **not** used.
- `fuzz` (optional): - `fuzz` (optional):
@ -110,12 +114,19 @@ def introspection():
additional test case. additional test case.
Note that this function is optional - but it makes sense to use it. 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. You would only skip this if `post_process` is used to fix checksums etc.
so you are using it e.g. as a post processing library. so if you are using it e.g. as a post processing library.
- `describe` (optional):
When this function is called, it shall describe the current testcase,
generated by the last mutation. This will be called, for example,
to name the written testcase file after a crash occurred.
Using it can help to reproduce crashing mutations.
- `havoc_mutation` and `havoc_mutation_probability` (optional): - `havoc_mutation` and `havoc_mutation_probability` (optional):
`havoc_mutation` performs a single custom mutation on a given input. This `havoc_mutation` performs a single custom mutation on a given input. This
mutation is stacked with the other mutations in havoc. The other method, mutation is stacked with other mutations in havoc. The other method,
`havoc_mutation_probability`, returns the probability that `havoc_mutation` `havoc_mutation_probability`, returns the probability that `havoc_mutation`
is called in havoc. By default, it is 6%. is called in havoc. By default, it is 6%.
@ -130,6 +141,9 @@ def introspection():
`post_process` function. This function is then transforming the data into the `post_process` function. This function is then transforming the data into the
format expected by the API before executing the target. format expected by the API before executing the target.
This can return any python object that implements the buffer protocol and
supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
- `queue_new_entry` (optional): - `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue. This methods is called after adding a new test case to the queue.
@ -168,7 +182,7 @@ trimmed input. Here's a quick API description:
on this input (e.g. if your input has n elements and you want to remove them on this input (e.g. if your input has n elements and you want to remove them
one by one, return n, if you do a binary search, return log(n), and so on). one by one, return n, if you do a binary search, return log(n), and so on).
If your trimming algorithm doesn't allow you to determine the amount of If your trimming algorithm doesn't allow to determine the amount of
(remaining) steps easily (esp. while running), then you can alternatively (remaining) steps easily (esp. while running), then you can alternatively
return 1 here and always return 0 in `post_trim` until you are finished and return 1 here and always return 0 in `post_trim` until you are finished and
no steps remain. In that case, returning 1 in `post_trim` will end the no steps remain. In that case, returning 1 in `post_trim` will end the
@ -210,19 +224,20 @@ Optionally, the following environment variables are supported:
- `AFL_PYTHON_ONLY` - `AFL_PYTHON_ONLY`
Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead.
trimming can cause the same test breakage like havoc and splice.
- `AFL_DEBUG` - `AFL_DEBUG`
When combined with `AFL_NO_UI`, this causes the C trimming code to emit additional messages about the performance and actions of your custom trimmer. Use this to see if it works :) When combined with `AFL_NO_UI`, this causes the C trimming code to emit
additional messages about the performance and actions of your custom
trimmer. Use this to see if it works :)
## 3) Usage ## 3) Usage
### Prerequisite ### Prerequisite
For Python mutator, the python 3 or 2 development package is required. On For Python mutators, the python 3 or 2 development package is required. On
Debian/Ubuntu/Kali this can be done: Debian/Ubuntu/Kali it can be installed like this:
```bash ```bash
sudo apt install python3-dev sudo apt install python3-dev
@ -240,13 +255,13 @@ In case your setup is different, set the necessary variables like this:
### Custom Mutator Preparation ### Custom Mutator Preparation
For C/C++ mutator, the source code must be compiled as a shared object: For C/C++ mutators, the source code must be compiled as a shared object:
```bash ```bash
gcc -shared -Wall -O3 example.c -o example.so gcc -shared -Wall -O3 example.c -o example.so
``` ```
Note that if you specify multiple custom mutators, the corresponding functions will Note that if you specify multiple custom mutators, the corresponding functions will
be called in the order in which they are specified. e.g first `post_process` function of be called in the order in which they are specified. e.g first `post_process` function of
`example_first.so` will be called and then that of `example_second.so` `example_first.so` will be called and then that of `example_second.so`.
### Run ### Run
@ -265,8 +280,8 @@ afl-fuzz /path/to/program
## 4) Example ## 4) Example
Please see [example.c](../examples/custom_mutators/example.c) and Please see [example.c](../utils/custom_mutators/example.c) and
[example.py](../examples/custom_mutators/example.py) [example.py](../utils/custom_mutators/example.py)
## 5) Other Resources ## 5) Other Resources

View File

@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead:
in your `$PATH`. in your `$PATH`.
- `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as. - `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as.
One possible use of this is examples/clang_asm_normalize/, which lets One possible use of this is utils/clang_asm_normalize/, which lets
you instrument hand-written assembly when compiling clang code by plugging you instrument hand-written assembly when compiling clang code by plugging
a normalizer into the chain. (There is no equivalent feature for GCC.) a normalizer into the chain. (There is no equivalent feature for GCC.)
@ -294,6 +294,9 @@ checks or alter some of the more exotic semantics of the tool:
on Linux systems. This slows things down, but lets you run more instances on Linux systems. This slows things down, but lets you run more instances
of afl-fuzz than would be prudent (if you really want to). of afl-fuzz than would be prudent (if you really want to).
- Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary
that is compiled into the target.
- `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input
queue. This can help with rare situations where a program crashes only queue. This can help with rare situations where a program crashes only
intermittently, but it's not really recommended under normal operating intermittently, but it's not really recommended under normal operating
@ -306,6 +309,14 @@ checks or alter some of the more exotic semantics of the tool:
don't want AFL++ to spend too much time classifying that stuff and just don't want AFL++ to spend too much time classifying that stuff and just
rapidly put all timeouts in that bin. rapidly put all timeouts in that bin.
- Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
to wait for the forkserver to spin up. The default is the `-t` value times
`FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
default would wait for `1000` milliseconds. Setting a different time here is useful
if the target has a very slow startup time, for example when doing
full-system fuzzing or emulation, but you don't want the actual runs
to wait too long for timeouts.
- `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics. - `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics.
This can be useful to speed up the fuzzing of text-based file formats. This can be useful to speed up the fuzzing of text-based file formats.
@ -380,8 +391,12 @@ checks or alter some of the more exotic semantics of the tool:
processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to
exit soon after the first crash is found. exit soon after the first crash is found.
- Setting `AFL_DEBUG_CHILD_OUTPUT` will not suppress the child output. - Setting `AFL_DEBUG_CHILD` will not suppress the child output.
This lets you see all output of the child, making setup issues obvious.
For example, in an unicornafl harness, you might see python stacktraces.
You may also see other logs that way, indicating why the forkserver won't start.
Not pretty but good for debugging purposes. Not pretty but good for debugging purposes.
Note that `AFL_DEBUG_CHILD_OUTPUT` is deprecated.
- Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color. - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color.
@ -389,6 +404,13 @@ checks or alter some of the more exotic semantics of the tool:
for an existing out folder, even if a different `-i` was provided. for an existing out folder, even if a different `-i` was provided.
Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir.
- Setting `AFL_MAX_DET_EXRAS` will change the threshold at what number of elements
in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will
kick off. In probabilistic mode not all dictionary entires will be used all
of the times for fuzzing mutations to not slow down fuzzing.
The default count is `200` elements. So for the 200 + 1st element, there is a
1 in 201 chance, that one of the dictionary entries will not be used directly.
- Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to
fork + execve() call for every tested input. This is useful mostly when fork + execve() call for every tested input. This is useful mostly when
working with unruly libraries that create threads or do other crazy working with unruly libraries that create threads or do other crazy
@ -406,6 +428,13 @@ checks or alter some of the more exotic semantics of the tool:
matches your StatsD server. matches your StatsD server.
Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`.
- Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash.
For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting
in an `-1` return code (i.e. `exit(-1)` got called), will be treated
as if a crash had ocurred.
This may be beneficial if you look for higher-level faulty conditions in which your
target still exits gracefully.
- Outdated environment variables that are not supported anymore: - Outdated environment variables that are not supported anymore:
`AFL_DEFER_FORKSRV` `AFL_DEFER_FORKSRV`
`AFL_PERSISTENT` `AFL_PERSISTENT`

View File

@ -78,10 +78,10 @@ Be sure to check out docs/sister_projects.md before writing your own.
## Need to fuzz the command-line arguments of a particular program? ## Need to fuzz the command-line arguments of a particular program?
You can find a simple solution in examples/argv_fuzzing. You can find a simple solution in utils/argv_fuzzing.
## Attacking a format that uses checksums? ## Attacking a format that uses checksums?
Remove the checksum-checking code or use a postprocessor! Remove the checksum-checking code or use a postprocessor!
See examples/custom_mutators/ for more. See utils/custom_mutators/ for more.

View File

@ -20,7 +20,7 @@ Because of this, fuzzing with ASAN is recommended only in four scenarios:
- Precisely gauge memory needs using http://jwilk.net/software/recidivm . - Precisely gauge memory needs using http://jwilk.net/software/recidivm .
- Limit the memory available to process using cgroups on Linux (see - Limit the memory available to process using cgroups on Linux (see
examples/asan_cgroups). utils/asan_cgroups).
To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The
afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags.
@ -74,7 +74,7 @@ There are also cgroups, but they are Linux-specific, not universally available
even on Linux systems, and they require root permissions to set up; I'm a bit even on Linux systems, and they require root permissions to set up; I'm a bit
hesitant to make afl-fuzz require root permissions just for that. That said, hesitant to make afl-fuzz require root permissions just for that. That said,
if you are on Linux and want to use cgroups, check out the contributed script if you are on Linux and want to use cgroups, check out the contributed script
that ships in examples/asan_cgroups/. that ships in utils/asan_cgroups/.
In settings where cgroups aren't available, we have no nice, portable way to In settings where cgroups aren't available, we have no nice, portable way to
avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for

View File

@ -152,7 +152,7 @@ write a simple script that performs two actions:
done done
``` ```
There is an example of such a script in examples/distributed_fuzzing/. There is an example of such a script in utils/distributed_fuzzing/.
There are other (older) more featured, experimental tools: There are other (older) more featured, experimental tools:
* https://github.com/richo/roving * https://github.com/richo/roving

View File

@ -113,6 +113,7 @@
#include <kstat.h> #include <kstat.h>
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include <sys/pset.h> #include <sys/pset.h>
#include <strings.h>
#endif #endif
#endif /* __linux__ */ #endif /* __linux__ */
@ -143,8 +144,8 @@ struct queue_entry {
u8 *fname; /* File name for the test case */ u8 *fname; /* File name for the test case */
u32 len; /* Input length */ u32 len; /* Input length */
u8 cal_failed, /* Calibration failed? */ u8 cal_failed; /* Calibration failed? */
trim_done, /* Trimmed? */ bool trim_done, /* Trimmed? */
was_fuzzed, /* historical, but needed for MOpt */ was_fuzzed, /* historical, but needed for MOpt */
passed_det, /* Deterministic stages passed? */ passed_det, /* Deterministic stages passed? */
has_new_cov, /* Triggers new coverage? */ has_new_cov, /* Triggers new coverage? */
@ -167,7 +168,8 @@ struct queue_entry {
u8 *trace_mini; /* Trace bytes, if kept */ u8 *trace_mini; /* Trace bytes, if kept */
u32 tc_ref; /* Trace bytes ref count */ u32 tc_ref; /* Trace bytes ref count */
double perf_score; /* performance score */ double perf_score, /* performance score */
weight;
u8 *testcase_buf; /* The testcase buffer, if loaded. */ u8 *testcase_buf; /* The testcase buffer, if loaded. */
@ -311,6 +313,7 @@ enum {
/* 10 */ PY_FUNC_QUEUE_GET, /* 10 */ PY_FUNC_QUEUE_GET,
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY, /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
/* 12 */ PY_FUNC_INTROSPECTION, /* 12 */ PY_FUNC_INTROSPECTION,
/* 13 */ PY_FUNC_DESCRIBE,
PY_FUNC_COUNT PY_FUNC_COUNT
}; };
@ -325,8 +328,7 @@ typedef struct py_mutator {
u8 * fuzz_buf; u8 * fuzz_buf;
size_t fuzz_size; size_t fuzz_size;
u8 * post_process_buf; Py_buffer post_process_buf;
size_t post_process_size;
u8 * trim_buf; u8 * trim_buf;
size_t trim_size; size_t trim_size;
@ -362,13 +364,14 @@ typedef struct afl_env_vars {
u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check, u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check,
afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
afl_bench_until_crash, afl_debug_child_output, afl_autoresume, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd; afl_cycle_schedules, afl_expand_havoc, afl_statsd;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
*afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries; *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
*afl_testcache_entries;
} afl_env_vars_t; } afl_env_vars_t;
@ -754,7 +757,7 @@ struct custom_mutator {
* When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can * When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can
* also give introspection information back with this function. * also give introspection information back with this function.
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @return pointer to a text string (const char*) * @return pointer to a text string (const char*)
*/ */
const char *(*afl_custom_introspection)(void *data); const char *(*afl_custom_introspection)(void *data);
@ -770,7 +773,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param buf Buffer containing the test case * @param buf Buffer containing the test case
* @param buf_size Size of the test case * @param buf_size Size of the test case
* @return The amount of fuzzes to perform on this queue entry, 0 = skip * @return The amount of fuzzes to perform on this queue entry, 0 = skip
@ -782,7 +785,7 @@ struct custom_mutator {
* *
* (Optional for now. Required in the future) * (Optional for now. Required in the future)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Pointer to the input data to be mutated and the mutated * @param[in] buf Pointer to the input data to be mutated and the mutated
* output * output
* @param[in] buf_size Size of the input/output data * @param[in] buf_size Size of the input/output data
@ -797,6 +800,21 @@ struct custom_mutator {
size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
u8 *add_buf, size_t add_buf_size, size_t max_size); u8 *add_buf, size_t add_buf_size, size_t max_size);
/**
* Describe the current testcase, generated by the last mutation.
* This will be called, for example, to give the written testcase a name
* after a crash ocurred. It can help to reproduce crashing mutations.
*
* (Optional)
*
* @param data pointer returned by afl_customm_init for this custom mutator
* @paramp[in] max_description_len maximum size avaliable for the description.
* A longer return string is legal, but will be truncated.
* @return A valid ptr to a 0-terminated string.
* An empty or NULL return will result in a default description
*/
const char *(*afl_custom_describe)(void *data, size_t max_description_len);
/** /**
* A post-processing function to use right before AFL writes the test case to * A post-processing function to use right before AFL writes the test case to
* disk in order to execute the target. * disk in order to execute the target.
@ -804,7 +822,7 @@ struct custom_mutator {
* (Optional) If this functionality is not needed, simply don't define this * (Optional) If this functionality is not needed, simply don't define this
* function. * function.
* *
* @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] data pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Buffer containing the test case to be executed * @param[in] buf Buffer containing the test case to be executed
* @param[in] buf_size Size of the test case * @param[in] buf_size Size of the test case
* @param[out] out_buf Pointer to the buffer storing the test case after * @param[out] out_buf Pointer to the buffer storing the test case after
@ -831,7 +849,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param buf Buffer containing the test case * @param buf Buffer containing the test case
* @param buf_size Size of the test case * @param buf_size Size of the test case
* @return The amount of possible iteration steps to trim the input. * @return The amount of possible iteration steps to trim the input.
@ -850,7 +868,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param[out] out_buf Pointer to the buffer containing the trimmed test case. * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
* The library can reuse a buffer for each call * The library can reuse a buffer for each call
* and will have to free the buf (for example in deinit) * and will have to free the buf (for example in deinit)
@ -865,7 +883,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param success Indicates if the last trim operation was successful. * @param success Indicates if the last trim operation was successful.
* @return The next trim iteration index (from 0 to the maximum amount of * @return The next trim iteration index (from 0 to the maximum amount of
* steps returned in init_trim). Negative on error. * steps returned in init_trim). Negative on error.
@ -878,7 +896,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] data pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Pointer to the input data to be mutated and the mutated * @param[in] buf Pointer to the input data to be mutated and the mutated
* output * output
* @param[in] buf_size Size of input data * @param[in] buf_size Size of input data
@ -897,7 +915,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @return The probability (0-100). * @return The probability (0-100).
*/ */
u8 (*afl_custom_havoc_mutation_probability)(void *data); u8 (*afl_custom_havoc_mutation_probability)(void *data);
@ -907,7 +925,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param filename File name of the test case in the queue entry * @param filename File name of the test case in the queue entry
* @return Return True(1) if the fuzzer will fuzz the queue entry, and * @return Return True(1) if the fuzzer will fuzz the queue entry, and
* False(0) otherwise. * False(0) otherwise.
@ -920,7 +938,7 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
* @param filename_new_queue File name of the new queue entry * @param filename_new_queue File name of the new queue entry
* @param filename_orig_queue File name of the original queue entry. This * @param filename_orig_queue File name of the original queue entry. This
* argument can be NULL while initializing the fuzzer * argument can be NULL while initializing the fuzzer
@ -930,7 +948,7 @@ struct custom_mutator {
/** /**
* Deinitialize the custom mutator. * Deinitialize the custom mutator.
* *
* @param data pointer returned in afl_custom_init for this fuzz case * @param data pointer returned in afl_custom_init by this custom mutator
*/ */
void (*afl_custom_deinit)(void *data); void (*afl_custom_deinit)(void *data);
@ -1006,7 +1024,7 @@ void classify_counts(afl_forkserver_t *);
void init_count_class16(void); void init_count_class16(void);
void minimize_bits(afl_state_t *, u8 *, u8 *); void minimize_bits(afl_state_t *, u8 *, u8 *);
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
u8 *describe_op(afl_state_t *, u8); u8 *describe_op(afl_state_t *, u8, size_t);
#endif #endif
u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *); u8 has_new_bits(afl_state_t *, u8 *);

View File

@ -636,7 +636,7 @@ struct afl_alloc_buf {
#define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf)) #define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf))
/* Returs the container element to this ptr */ /* Returns the container element to this ptr */
static inline struct afl_alloc_buf *afl_alloc_bufptr(void *buf) { static inline struct afl_alloc_buf *afl_alloc_bufptr(void *buf) {
return (struct afl_alloc_buf *)((u8 *)buf - AFL_ALLOC_SIZE_OFFSET); return (struct afl_alloc_buf *)((u8 *)buf - AFL_ALLOC_SIZE_OFFSET);
@ -694,12 +694,18 @@ static inline void *afl_realloc(void **buf, size_t size_needed) {
} }
/* alloc */ /* alloc */
new_buf = (struct afl_alloc_buf *)realloc(new_buf, next_size); struct afl_alloc_buf *newer_buf =
if (unlikely(!new_buf)) { (struct afl_alloc_buf *)realloc(new_buf, next_size);
if (unlikely(!newer_buf)) {
free(new_buf); // avoid a leak
*buf = NULL; *buf = NULL;
return NULL; return NULL;
} else {
new_buf = newer_buf;
} }
new_buf->complete_size = next_size; new_buf->complete_size = next_size;
@ -730,12 +736,18 @@ static inline void *afl_realloc_exact(void **buf, size_t size_needed) {
if (unlikely(current_size == size_needed)) { return *buf; } if (unlikely(current_size == size_needed)) { return *buf; }
/* alloc */ /* alloc */
new_buf = (struct afl_alloc_buf *)realloc(new_buf, size_needed); struct afl_alloc_buf *newer_buf =
if (unlikely(!new_buf)) { (struct afl_alloc_buf *)realloc(new_buf, size_needed);
if (unlikely(!newer_buf)) {
free(new_buf); // avoid a leak
*buf = NULL; *buf = NULL;
return NULL; return NULL;
} else {
new_buf = newer_buf;
} }
new_buf->complete_size = size_needed; new_buf->complete_size = size_needed;

View File

@ -31,14 +31,14 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <stdbool.h>
#include "types.h" #include "types.h"
#include "stdbool.h"
/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */ /* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
#define STRINGIFY_VAL_SIZE_MAX (16) #define STRINGIFY_VAL_SIZE_MAX (16)
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin); void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
void check_environment_vars(char **env); void check_environment_vars(char **env);
char **argv_cpy_dup(int argc, char **argv); char **argv_cpy_dup(int argc, char **argv);

View File

@ -270,6 +270,16 @@
\ \
} while (0) } while (0)
/* Show a prefixed debug output. */
#define DEBUGF(x...) \
do { \
\
SAYF(cMGN "[D] " cBRI "DEBUG: " cRST x); \
SAYF(cRST ""); \
\
} while (0)
/* Error-checking versions of read() and write() that call RPFATAL() as /* Error-checking versions of read() and write() that call RPFATAL() as
appropriate. */ appropriate. */

View File

@ -6,6 +6,7 @@ static char *afl_environment_deprecated[] = {
"AFL_LLVM_WHITELIST", "AFL_LLVM_WHITELIST",
"AFL_GCC_WHITELIST", "AFL_GCC_WHITELIST",
"AFL_DEBUG_CHILD_OUTPUT",
"AFL_DEFER_FORKSRV", "AFL_DEFER_FORKSRV",
"AFL_POST_LIBRARY", "AFL_POST_LIBRARY",
"AFL_PERSISTENT", "AFL_PERSISTENT",
@ -31,12 +32,13 @@ static char *afl_environment_variables[] = {
"AFL_CODE_START", "AFL_CODE_START",
"AFL_COMPCOV_BINNAME", "AFL_COMPCOV_BINNAME",
"AFL_COMPCOV_LEVEL", "AFL_COMPCOV_LEVEL",
"AFL_CRASH_EXITCODE",
"AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_MUTATOR_ONLY",
"AFL_CXX", "AFL_CXX",
"AFL_CYCLE_SCHEDULES", "AFL_CYCLE_SCHEDULES",
"AFL_DEBUG", "AFL_DEBUG",
"AFL_DEBUG_CHILD_OUTPUT", "AFL_DEBUG_CHILD",
"AFL_DEBUG_GDB", "AFL_DEBUG_GDB",
"AFL_DISABLE_TRIM", "AFL_DISABLE_TRIM",
"AFL_DONT_OPTIMIZE", "AFL_DONT_OPTIMIZE",
@ -99,6 +101,7 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID", "AFL_LLVM_LTO_DONTWRITEID",
"AFL_NO_ARITH", "AFL_NO_ARITH",
"AFL_NO_AUTODICT",
"AFL_NO_BUILTIN", "AFL_NO_BUILTIN",
"AFL_NO_CPU_RED", "AFL_NO_CPU_RED",
"AFL_NO_FORKSRV", "AFL_NO_FORKSRV",
@ -123,6 +126,7 @@ static char *afl_environment_variables[] = {
"AFL_QEMU_PERSISTENT_CNT", "AFL_QEMU_PERSISTENT_CNT",
"AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_GPR",
"AFL_QEMU_PERSISTENT_HOOK", "AFL_QEMU_PERSISTENT_HOOK",
"AFL_QEMU_PERSISTENT_MEM",
"AFL_QEMU_PERSISTENT_RET", "AFL_QEMU_PERSISTENT_RET",
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET", "AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
"AFL_QEMU_PERSISTENT_EXITS", "AFL_QEMU_PERSISTENT_EXITS",

View File

@ -37,9 +37,7 @@ typedef struct afl_forkserver {
/* a program that includes afl-forkserver needs to define these */ /* a program that includes afl-forkserver needs to define these */
u8 uses_asan; /* Target uses ASAN? */
u8 *trace_bits; /* SHM with instrumentation bitmap */ u8 *trace_bits; /* SHM with instrumentation bitmap */
u8 use_stdin; /* use stdin for sending data */
s32 fsrv_pid, /* PID of the fork server */ s32 fsrv_pid, /* PID of the fork server */
child_pid, /* PID of the fuzzed program */ child_pid, /* PID of the fuzzed program */
@ -53,8 +51,6 @@ typedef struct afl_forkserver {
fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */ fsrv_st_fd; /* Fork server status pipe (read) */
u8 no_unlink; /* do not unlink cur_input */
u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 exec_tmout; /* Configurable exec timeout (ms) */
u32 init_tmout; /* Configurable init timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */
u32 map_size; /* map size used by the target */ u32 map_size; /* map size used by the target */
@ -73,13 +69,22 @@ typedef struct afl_forkserver {
u8 last_kill_signal; /* Signal that killed the child */ u8 last_kill_signal; /* Signal that killed the child */
u8 use_shmem_fuzz; /* use shared mem for test cases */ bool use_shmem_fuzz; /* use shared mem for test cases */
u8 support_shmem_fuzz; /* set by afl-fuzz */ bool support_shmem_fuzz; /* set by afl-fuzz */
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ bool use_fauxsrv; /* Fauxsrv for non-forking targets? */
u8 qemu_mode; /* if running in qemu mode or not */ bool qemu_mode; /* if running in qemu mode or not */
bool use_stdin; /* use stdin for sending data */
bool no_unlink; /* do not unlink cur_input */
bool uses_asan; /* Target uses ASAN? */
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
u8 crash_exitcode; /* The crash exitcode specified */
u32 *shmem_fuzz_len; /* length of the fuzzing test case */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */

View File

@ -268,8 +268,8 @@ struct InsTrim : public ModulePass {
for (auto &BB : F) for (auto &BB : F)
if (BB.size() > 0) ++bb_cnt; if (BB.size() > 0) ++bb_cnt;
SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n", DEBUGF("Function %s size %zu %u\n", F.getName().str().c_str(), F.size(),
F.getName().str().c_str(), F.size(), bb_cnt); bb_cnt);
} }

View File

@ -147,7 +147,7 @@ The numerical value specified within the loop controls the maximum number
of iterations before AFL will restart the process from scratch. This minimizes of iterations before AFL will restart the process from scratch. This minimizes
the impact of memory leaks and similar glitches; 1000 is a good starting point. the impact of memory leaks and similar glitches; 1000 is a good starting point.
A more detailed template is shown in ../examples/persistent_demo/. A more detailed template is shown in ../utils/persistent_mode/.
Similarly to the previous mode, the feature works only with afl-gcc-fast or Similarly to the previous mode, the feature works only with afl-gcc-fast or
afl-clang-fast; #ifdef guards can be used to suppress it when using other afl-clang-fast; #ifdef guards can be used to suppress it when using other
compilers. compilers.

View File

@ -60,7 +60,12 @@ AUTODICTIONARY: 11 strings found
## Getting llvm 11+ ## Getting llvm 11+
### Installing llvm from the llvm repository (version 11) ### Installing llvm version 11
llvm 11 should be available in all current Linux repositories.
If you use an outdated Linux distribution read the next section.
### Installing llvm from the llvm repository (version 12)
Installing the llvm snapshot builds is easy and mostly painless: Installing the llvm snapshot builds is easy and mostly painless:
@ -73,11 +78,11 @@ then add the pgp key of llvm and install the packages:
``` ```
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update && apt-get upgrade -y apt-get update && apt-get upgrade -y
apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \ apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \ libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \ libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \ liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools
``` ```
### Building llvm yourself (version 12) ### Building llvm yourself (version 12)
@ -120,16 +125,22 @@ While compiling, a dictionary based on string comparisons is automatically
generated and put into the target binary. This dictionary is transfered to afl-fuzz generated and put into the target binary. This dictionary is transfered to afl-fuzz
on start. This improves coverage statistically by 5-10% :) on start. This improves coverage statistically by 5-10% :)
Note that if for any reason you do not want to use the autodictionary feature
then just set the environment variable `AFL_NO_AUTODICT` when starting afl-fuzz.
## Fixed memory map ## Fixed memory map
To speed up fuzzing, it is possible to set a fixed shared memory map. To speed up fuzzing a little bit more, it is possible to set a fixed shared
memory map.
Recommended is the value 0x10000. Recommended is the value 0x10000.
In most cases this will work without any problems. However if a target uses In most cases this will work without any problems. However if a target uses
early constructors, ifuncs or a deferred forkserver this can crash the target. early constructors, ifuncs or a deferred forkserver this can crash the target.
On unusual operating systems/processors/kernels or weird libraries this might
fail so to change the fixed address at compile time set Also on unusual operating systems/processors/kernels or weird libraries the
AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address recommended 0x10000 address might not work, so then change the fixed address.
to be dynamic - the original afl way, which is slower).
To enable this feature set AFL_LLVM_MAP_ADDR with the address.
## Document edge IDs ## Document edge IDs

View File

@ -11,7 +11,7 @@ and that its state can be resetted so that multiple calls can be performed
without resource leaks and former runs having no impact on following runs without resource leaks and former runs having no impact on following runs
(this can be seen by the `stability` indicator in the `afl-fuzz` UI). (this can be seen by the `stability` indicator in the `afl-fuzz` UI).
Examples can be found in [examples/persistent_mode](../examples/persistent_mode). Examples can be found in [utils/persistent_mode](../utils/persistent_mode).
## 2) TLDR; ## 2) TLDR;
@ -23,15 +23,20 @@ __AFL_FUZZ_INIT();
main() { main() {
// anything else here, eg. command line arguments, initialization, etc.
#ifdef __AFL_HAVE_MANUAL_CONTROL #ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT(); __AFL_INIT();
#endif #endif
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT
// and before __AFL_LOOP!
while (__AFL_LOOP(10000)) { while (__AFL_LOOP(10000)) {
int len = __AFL_FUZZ_TESTCASE_LEN; int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a
// call!
if (len < 8) continue; // check for a required/useful minimum input length if (len < 8) continue; // check for a required/useful minimum input length
/* Setup function call, e.g. struct target *tmp = libtarget_init() */ /* Setup function call, e.g. struct target *tmp = libtarget_init() */
@ -110,37 +115,13 @@ With the location selected, add this code in the appropriate spot:
``` ```
You don't need the #ifdef guards, but including them ensures that the program You don't need the #ifdef guards, but including them ensures that the program
will keep working normally when compiled with a tool other than afl-clang-fast. will keep working normally when compiled with a tool other than afl-clang-fast/
afl-clang-lto/afl-gcc-fast.
Finally, recompile the program with afl-clang-fast/lto (afl-gcc or afl-clang will Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
*not* generate a deferred-initialization binary) - and you should be all set! (afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
and you should be all set!
*NOTE:* In the code between `main` and `__AFL_INIT()` should not be any code
run that is instrumented - otherwise a crash might occure.
In case this is useful (e.g. for expensive one time initialization) you can
try to do the following:
Add after the includes:
```
extern unsigned char *__afl_area_ptr;
#define MAX_DUMMY_SIZE 256000
__attribute__((constructor(1))) void __afl_protect(void) {
#ifdef MAP_FIXED_NOREPLACE
__afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if ((uint64_t)__afl_area_ptr == -1)
#endif
__afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if ((uint64_t)__afl_area_ptr == -1)
__afl_area_ptr = (unsigned char*) mmap(NULL, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
```
and just before `__AFL_INIT()`:
```
munmap(__afl_area_ptr, MAX_DUMMY_SIZE);
__afl_area_ptr = NULL;
```
## 4) Persistent mode ## 4) Persistent mode
@ -169,7 +150,7 @@ the impact of memory leaks and similar glitches; 1000 is a good starting point,
and going much higher increases the likelihood of hiccups without giving you and going much higher increases the likelihood of hiccups without giving you
any real performance benefits. any real performance benefits.
A more detailed template is shown in ../examples/persistent_demo/. A more detailed template is shown in ../utils/persistent_mode/.
Similarly to the previous mode, the feature works only with afl-clang-fast; #ifdef Similarly to the previous mode, the feature works only with afl-clang-fast; #ifdef
guards can be used to suppress it when using other compilers. guards can be used to suppress it when using other compilers.

View File

@ -544,7 +544,9 @@ bool ModuleSanitizerCoverage::instrumentModule(
be_quiet = 1; be_quiet = 1;
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
// scanForDangerousFunctions(&M);
initInstrumentList();
scanForDangerousFunctions(&M);
if (debug) { if (debug) {
@ -819,6 +821,8 @@ void ModuleSanitizerCoverage::instrumentFunction(
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
if (F.empty()) return; if (F.empty()) return;
if (!isInInstrumentList(&F)) return;
if (F.getName().find(".module_ctor") != std::string::npos) if (F.getName().find(".module_ctor") != std::string::npos)
return; // Should not instrument sanitizer init functions. return; // Should not instrument sanitizer init functions.
if (F.getName().startswith("__sanitizer_")) if (F.getName().startswith("__sanitizer_"))
@ -1123,11 +1127,11 @@ void ModuleSanitizerCoverage::InjectTraceForCmp(
Value * A1 = ICMP->getOperand(1); Value * A1 = ICMP->getOperand(1);
if (!A0->getType()->isIntegerTy()) continue; if (!A0->getType()->isIntegerTy()) continue;
uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType()); uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType());
int CallbackIdx = int CallbackIdx = TypeSize == 8 ? 0
TypeSize == 8 : TypeSize == 16 ? 1
? 0 : TypeSize == 32 ? 2
: TypeSize == 16 ? 1 : TypeSize == 64 ? 3
: TypeSize == 32 ? 2 : TypeSize == 64 ? 3 : -1; : -1;
if (CallbackIdx < 0) continue; if (CallbackIdx < 0) continue;
// __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1);
auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx];
@ -1315,6 +1319,7 @@ std::string ModuleSanitizerCoverage::getSectionEnd(
} }
char ModuleSanitizerCoverageLegacyPass::ID = 0; char ModuleSanitizerCoverageLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov", INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
"Pass for instrumenting coverage on functions", false, "Pass for instrumenting coverage on functions", false,
false) false)
@ -1323,6 +1328,7 @@ INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov", INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
"Pass for instrumenting coverage on functions", false, "Pass for instrumenting coverage on functions", false,
false) false)
ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
const SanitizerCoverageOptions &Options, const SanitizerCoverageOptions &Options,
const std::vector<std::string> &AllowlistFiles, const std::vector<std::string> &AllowlistFiles,

View File

@ -101,6 +101,11 @@ int __afl_sharedmem_fuzzing __attribute__((weak));
struct cmp_map *__afl_cmp_map; struct cmp_map *__afl_cmp_map;
/* Child pid? */
static s32 child_pid;
static void (*old_sigterm_handler)(int) = 0;
/* Running in persistent mode? */ /* Running in persistent mode? */
static u8 is_persistent; static u8 is_persistent;
@ -109,6 +114,14 @@ static u8 is_persistent;
static u8 _is_sancov; static u8 _is_sancov;
/* ensure we kill the child on termination */
void at_exit(int signal) {
if (child_pid > 0) { kill(child_pid, SIGKILL); }
}
/* Uninspired gcc plugin instrumentation */ /* Uninspired gcc plugin instrumentation */
void __afl_trace(const u32 x) { void __afl_trace(const u32 x) {
@ -150,6 +163,12 @@ static void __afl_map_shm_fuzz() {
char *id_str = getenv(SHM_FUZZ_ENV_VAR); char *id_str = getenv(SHM_FUZZ_ENV_VAR);
if (getenv("AFL_DEBUG")) {
fprintf(stderr, "DEBUG: fuzzcase shmem %s\n", id_str ? id_str : "none");
}
if (id_str) { if (id_str) {
u8 *map = NULL; u8 *map = NULL;
@ -182,7 +201,8 @@ static void __afl_map_shm_fuzz() {
if (!map || map == (void *)-1) { if (!map || map == (void *)-1) {
perror("Could not access fuzzign shared memory"); perror("Could not access fuzzing shared memory");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1); exit(1);
} }
@ -199,6 +219,7 @@ static void __afl_map_shm_fuzz() {
} else { } else {
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n"); fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1); exit(1);
} }
@ -322,6 +343,8 @@ static void __afl_map_shm(void) {
send_forkserver_error(FS_ERROR_MAP_ADDR); send_forkserver_error(FS_ERROR_MAP_ADDR);
else else
send_forkserver_error(FS_ERROR_MMAP); send_forkserver_error(FS_ERROR_MMAP);
perror("mmap for map");
exit(2); exit(2);
} }
@ -332,20 +355,22 @@ static void __afl_map_shm(void) {
__afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0); __afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0);
#endif
/* Whooooops. */ /* Whooooops. */
if (__afl_area_ptr == (void *)-1) { if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
if (__afl_map_addr) if (__afl_map_addr)
send_forkserver_error(FS_ERROR_MAP_ADDR); send_forkserver_error(FS_ERROR_MAP_ADDR);
else else
send_forkserver_error(FS_ERROR_SHMAT); send_forkserver_error(FS_ERROR_SHMAT);
perror("shmat for map");
_exit(1); _exit(1);
} }
#endif
/* Write something into the bitmap so that even with low AFL_INST_RATIO, /* Write something into the bitmap so that even with low AFL_INST_RATIO,
our parent doesn't give up on us. */ our parent doesn't give up on us. */
@ -363,6 +388,7 @@ static void __afl_map_shm(void) {
fprintf(stderr, "can not acquire mmap for address %p\n", fprintf(stderr, "can not acquire mmap for address %p\n",
(void *)__afl_map_addr); (void *)__afl_map_addr);
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1); exit(1);
} }
@ -397,7 +423,8 @@ static void __afl_map_shm(void) {
shm_fd = shm_open(shm_file_path, O_RDWR, 0600); shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
if (shm_fd == -1) { if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n"); perror("shm_open() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1); exit(1);
} }
@ -411,6 +438,7 @@ static void __afl_map_shm(void) {
shm_fd = -1; shm_fd = -1;
fprintf(stderr, "mmap() failed\n"); fprintf(stderr, "mmap() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(2); exit(2);
} }
@ -422,7 +450,13 @@ static void __afl_map_shm(void) {
__afl_cmp_map = shmat(shm_id, NULL, 0); __afl_cmp_map = shmat(shm_id, NULL, 0);
#endif #endif
if (__afl_cmp_map == (void *)-1) _exit(1); if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) {
perror("shmat for cmplog");
send_forkserver_error(FS_ERROR_SHM_OPEN);
_exit(1);
}
} }
@ -432,7 +466,6 @@ static void __afl_map_shm(void) {
static void __afl_start_snapshots(void) { static void __afl_start_snapshots(void) {
static u8 tmp[4] = {0, 0, 0, 0}; static u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0; u32 status = 0;
u32 already_read_first = 0; u32 already_read_first = 0;
u32 was_killed; u32 was_killed;
@ -579,6 +612,7 @@ static void __afl_start_snapshots(void) {
//(void)nice(-20); // does not seem to improve //(void)nice(-20); // does not seem to improve
signal(SIGCHLD, old_sigchld_handler); signal(SIGCHLD, old_sigchld_handler);
signal(SIGTERM, old_sigterm_handler);
close(FORKSRV_FD); close(FORKSRV_FD);
close(FORKSRV_FD + 1); close(FORKSRV_FD + 1);
@ -633,6 +667,11 @@ static void __afl_start_snapshots(void) {
static void __afl_start_forkserver(void) { static void __afl_start_forkserver(void) {
struct sigaction orig_action;
sigaction(SIGTERM, NULL, &orig_action);
old_sigterm_handler = orig_action.sa_handler;
signal(SIGTERM, at_exit);
#ifdef __linux__ #ifdef __linux__
if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") && if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
afl_snapshot_init() >= 0) { afl_snapshot_init() >= 0) {
@ -645,7 +684,6 @@ static void __afl_start_forkserver(void) {
#endif #endif
u8 tmp[4] = {0, 0, 0, 0}; u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0; u32 status = 0;
u32 already_read_first = 0; u32 already_read_first = 0;
u32 was_killed; u32 was_killed;
@ -793,6 +831,7 @@ static void __afl_start_forkserver(void) {
//(void)nice(-20); //(void)nice(-20);
signal(SIGCHLD, old_sigchld_handler); signal(SIGCHLD, old_sigchld_handler);
signal(SIGTERM, old_sigterm_handler);
close(FORKSRV_FD); close(FORKSRV_FD);
close(FORKSRV_FD + 1); close(FORKSRV_FD + 1);
@ -992,7 +1031,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
// For stability analysis, if you want to know to which function unstable // For stability analysis, if you want to know to which function unstable
// edge IDs belong - uncomment, recompile+install llvm_mode, recompile // edge IDs belong - uncomment, recompile+install llvm_mode, recompile
// the target. libunwind and libbacktrace are better solutions. // the target. libunwind and libbacktrace are better solutions.
// Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture // Set AFL_DEBUG_CHILD=1 and run afl-fuzz with 2>file to capture
// the backtrace output // the backtrace output
/* /*
uint32_t unstable[] = { ... unstable edge IDs }; uint32_t unstable[] = { ... unstable edge IDs };

View File

@ -627,9 +627,8 @@ struct afl_pass : gimple_opt_pass {
} }
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
"loaded allowlist with %zu file and %zu function entries\n", allowListFiles.size(), allowListFunctions.size());
allowListFiles.size(), allowListFunctions.size());
} }
@ -702,9 +701,8 @@ struct afl_pass : gimple_opt_pass {
} }
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF("loaded denylist with %zu file and %zu function entries\n",
"loaded denylist with %zu file and %zu function entries\n", denyListFiles.size(), denyListFunctions.size());
denyListFiles.size(), denyListFunctions.size());
} }
@ -745,10 +743,10 @@ struct afl_pass : gimple_opt_pass {
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the deny function list, " "Function %s is in the deny function list, not "
"not instrumenting ... \n", "instrumenting ... \n",
instFunction.c_str()); instFunction.c_str());
return false; return false;
} }
@ -825,10 +823,10 @@ struct afl_pass : gimple_opt_pass {
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the allow function list, " "Function %s is in the allow function list, instrumenting "
"instrumenting ... \n", "... \n",
instFunction.c_str()); instFunction.c_str());
return true; return true;
} }
@ -859,11 +857,11 @@ struct afl_pass : gimple_opt_pass {
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the allowlist (%s), " "Function %s is in the allowlist (%s), instrumenting ... "
"instrumenting ... \n", "\n",
IDENTIFIER_POINTER(DECL_NAME(F->decl)), IDENTIFIER_POINTER(DECL_NAME(F->decl)),
source_file.c_str()); source_file.c_str());
return true; return true;
} }

View File

@ -173,9 +173,8 @@ void initInstrumentList() {
} }
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
"loaded allowlist with %zu file and %zu function entries\n", allowListFiles.size(), allowListFunctions.size());
allowListFiles.size(), allowListFunctions.size());
} }
@ -248,9 +247,8 @@ void initInstrumentList() {
} }
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF("loaded denylist with %zu file and %zu function entries\n",
"loaded denylist with %zu file and %zu function entries\n", denyListFiles.size(), denyListFunctions.size());
denyListFiles.size(), denyListFunctions.size());
} }
@ -409,10 +407,10 @@ bool isInInstrumentList(llvm::Function *F) {
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the deny function list, " "Function %s is in the deny function list, not instrumenting "
"not instrumenting ... \n", "... \n",
instFunction.c_str()); instFunction.c_str());
return false; return false;
} }
@ -489,10 +487,10 @@ bool isInInstrumentList(llvm::Function *F) {
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the allow function list, " "Function %s is in the allow function list, instrumenting "
"instrumenting ... \n", "... \n",
instFunction.c_str()); instFunction.c_str());
return true; return true;
} }
@ -523,10 +521,10 @@ bool isInInstrumentList(llvm::Function *F) {
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) { if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"Function %s is in the allowlist (%s), " "Function %s is in the allowlist (%s), instrumenting ... "
"instrumenting ... \n", "\n",
F->getName().str().c_str(), source_file.c_str()); F->getName().str().c_str(), source_file.c_str());
return true; return true;
} }

View File

@ -105,15 +105,14 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
if (isInInstrumentList(&F)) { if (isInInstrumentList(&F)) {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n", DEBUGF("function %s is in the instrument file list\n",
F.getName().str().c_str()); F.getName().str().c_str());
} else { } else {
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF("function %s is NOT in the instrument file list\n",
"function %s is NOT in the instrument file list\n", F.getName().str().c_str());
F.getName().str().c_str());
auto & Ctx = F.getContext(); auto & Ctx = F.getContext();
AttributeList Attrs = F.getAttributes(); AttributeList Attrs = F.getAttributes();

View File

@ -601,15 +601,12 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; } if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; }
const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits(); const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits();
const unsigned int precision = const unsigned int precision = sizeInBits == 32 ? 24
sizeInBits == 32 : sizeInBits == 64 ? 53
? 24 : sizeInBits == 128 ? 113
: sizeInBits == 64 : sizeInBits == 16 ? 11
? 53 /* sizeInBits == 80 */
: sizeInBits == 128 ? 113 : 65;
: sizeInBits == 16 ? 11
/* sizeInBits == 80 */
: 65;
const unsigned shiftR_exponent = precision - 1; const unsigned shiftR_exponent = precision - 1;
const unsigned long long mask_fraction = const unsigned long long mask_fraction =

View File

@ -1,6 +1,6 @@
# libdislocator, an abusive allocator # libdislocator, an abusive allocator
(See ../docs/README.md for the general instruction manual.) (See ../README.md for the general instruction manual.)
This is a companion library that can be used as a drop-in replacement for the This is a companion library that can be used as a drop-in replacement for the
libc allocator in the fuzzed binaries. It improves the odds of bumping into libc allocator in the fuzzed binaries. It improves the odds of bumping into

View File

@ -1,6 +1,6 @@
# strcmp() / memcmp() token capture library # strcmp() / memcmp() token capture library
(See ../docs/README.md for the general instruction manual.) (See ../README.md for the general instruction manual.)
This companion library allows you to instrument `strcmp()`, `memcmp()`, This companion library allows you to instrument `strcmp()`, `memcmp()`,
and related functions to automatically extract syntax tokens passed to any of and related functions to automatically extract syntax tokens passed to any of

View File

@ -44,7 +44,7 @@ target_func p_target_func = NULL;
rword module_base = 0; rword module_base = 0;
rword module_end = 0; rword module_end = 0;
static unsigned char static unsigned char
dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */ dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */
unsigned char *afl_area_ptr = NULL; /* Exported for afl_gen_trace */ unsigned char *afl_area_ptr = NULL; /* Exported for afl_gen_trace */
unsigned long afl_prev_loc = 0; unsigned long afl_prev_loc = 0;

View File

@ -1,6 +1,6 @@
# High-performance binary-only instrumentation for afl-fuzz # High-performance binary-only instrumentation for afl-fuzz
(See ../docs/README.md for the general instruction manual.) (See ../README.md for the general instruction manual.)
## 1) Introduction ## 1) Introduction
@ -179,7 +179,7 @@ match.
## 12) Gotchas, feedback, bugs ## 12) Gotchas, feedback, bugs
If you need to fix up checksums or do other cleanup on mutated test cases, see If you need to fix up checksums or do other cleanup on mutated test cases, see
examples/custom_mutators/ for a viable solution. utils/custom_mutators/ for a viable solution.
Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate
the "shadow VM" trick employed by the sanitizers and will probably just the "shadow VM" trick employed by the sanitizers and will probably just

View File

@ -172,4 +172,4 @@ and so the input_buf variables of the hook becomes meaningful. Otherwise,
you have to read the input from a file like stdin. you have to read the input from a file like stdin.
An example that you can use with little modification for your target can An example that you can use with little modification for your target can
be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook) be found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook)

View File

@ -114,7 +114,7 @@ git status 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "[*] initializing qemuafl submodule" echo "[*] initializing qemuafl submodule"
git submodule init || exit 1 git submodule init || exit 1
git submodule update 2>/dev/null # ignore errors git submodule update ./qemuafl 2>/dev/null # ignore errors
else else
echo "[*] cloning qemuafl" echo "[*] cloning qemuafl"
test -d qemuafl || { test -d qemuafl || {

@ -1 +1 @@
Subproject commit d66c9e2654efa8939f0fe6995d11a72b98a4da3e Subproject commit 21ff34383764a8c6f66509b3b8d5282468c721e1

View File

@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static s32 dev_null_fd = -1; /* FD to /dev/null */ static s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 edges_only, /* Ignore hit counts? */ static bool edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */ use_hex_offsets, /* Show hex offsets? */
use_stdin = 1; /* Use stdin for program input? */ use_stdin = true; /* Use stdin for program input? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_timed_out; /* Child timed out? */ child_timed_out; /* Child timed out? */

View File

@ -27,7 +27,7 @@
utility has right now is to be able to skip them gracefully and allow the utility has right now is to be able to skip them gracefully and allow the
compilation process to continue. compilation process to continue.
That said, see examples/clang_asm_normalize/ for a solution that may That said, see utils/clang_asm_normalize/ for a solution that may
allow clang users to make things work even with hand-crafted assembly. Just allow clang users to make things work even with hand-crafted assembly. Just
note that there is no equivalent for GCC. note that there is no equivalent for GCC.

View File

@ -48,15 +48,16 @@
static u8 * obj_path; /* Path to runtime libraries */ static u8 * obj_path; /* Path to runtime libraries */
static u8 **cc_params; /* Parameters passed to the real CC */ static u8 **cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */ static u32 cc_par_cnt = 1; /* Param count, including argv0 */
static u8 clang_mode; /* Invoked as afl-clang*? */
static u8 llvm_fullpath[PATH_MAX]; static u8 llvm_fullpath[PATH_MAX];
static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode, static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode;
compiler_mode, plusplus_mode; static u8 compiler_mode, plusplus_mode, have_instr_env = 0;
static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto; static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
static u8 *lto_flag = AFL_CLANG_FLTO, *argvnull; static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
static u8 debug; static u8 debug;
static u8 cwd[4096]; static u8 cwd[4096];
static u8 cmplog_mode; static u8 cmplog_mode;
u8 use_stdin; /* dummy */ u8 use_stdin; /* dummy */
// static u8 *march_opt = CFLAGS_OPT; // static u8 *march_opt = CFLAGS_OPT;
enum { enum {
@ -105,20 +106,43 @@ u8 *getthecwd() {
} }
/* Try to find the runtime libraries. If that fails, abort. */ /* Try to find a specific runtime we need, returns NULL on fail. */
/*
in find_object() we look here:
1. if obj_path is already set we look there first
2. then we check the $AFL_PATH environment variable location if set
3. next we check argv[0] if it has path information and use it
a) we also check ../lib/afl
4. if 3. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
FreeBSD with procfs)
a) and check here in ../lib/afl too
5. we look into the AFL_PATH define (usually /usr/local/lib/afl)
6. we finally try the current directory
if all these attempts fail - we return NULL and the caller has to decide
what to do.
*/
static u8 *find_object(u8 *obj, u8 *argv0) { static u8 *find_object(u8 *obj, u8 *argv0) {
u8 *afl_path = getenv("AFL_PATH"); u8 *afl_path = getenv("AFL_PATH");
u8 *slash = NULL, *tmp; u8 *slash = NULL, *tmp;
if (obj_path) {
tmp = alloc_printf("%s/%s", obj_path, obj);
if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
}
if (afl_path) { if (afl_path) {
#ifdef __ANDROID__
tmp = alloc_printf("%s/%s", afl_path, obj); tmp = alloc_printf("%s/%s", afl_path, obj);
#else
tmp = alloc_printf("%s/%s", afl_path, obj);
#endif
if (!access(tmp, R_OK)) { if (!access(tmp, R_OK)) {
@ -131,128 +155,130 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
} }
if (argv0) slash = strrchr(argv0, '/'); if (argv0) {
if (slash) { slash = strrchr(argv0, '/');
u8 *dir; if (slash) {
*slash = 0; u8 *dir = ck_strdup(argv0);
dir = ck_strdup(argv0);
*slash = '/';
#ifdef __ANDROID__ slash = strrchr(dir, '/');
tmp = alloc_printf("%s/%s", dir, obj); *slash = 0;
#else
tmp = alloc_printf("%s/%s", dir, obj);
#endif
if (!access(tmp, R_OK)) { tmp = alloc_printf("%s/%s", dir, obj);
obj_path = dir; if (!access(tmp, R_OK)) {
return tmp;
obj_path = dir;
return tmp;
}
ck_free(tmp);
tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
if (!access(tmp, R_OK)) {
u8 *dir2 = alloc_printf("%s/../lib/afl", dir);
obj_path = dir2;
ck_free(dir);
return tmp;
}
ck_free(tmp);
ck_free(dir);
} }
ck_free(tmp); #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
ck_free(dir); defined(__ANDROID__) || defined(__NetBSD__)
#define HAS_PROC_FS 1
#endif
#ifdef HAS_PROC_FS
else {
char *procname = NULL;
#if defined(__FreeBSD__) || defined(__DragonFly__)
procname = "/proc/curproc/file";
#elif defined(__linux__) || defined(__ANDROID__)
procname = "/proc/self/exe";
#elif defined(__NetBSD__)
procname = "/proc/curproc/exe";
#endif
if (procname) {
char exepath[PATH_MAX];
ssize_t exepath_len = readlink(procname, exepath, sizeof(exepath));
if (exepath_len > 0 && exepath_len < PATH_MAX) {
exepath[exepath_len] = 0;
slash = strrchr(exepath, '/');
if (slash) {
*slash = 0;
tmp = alloc_printf("%s/%s", exepath, obj);
if (!access(tmp, R_OK)) {
u8 *dir = alloc_printf("%s", exepath);
obj_path = dir;
return tmp;
}
ck_free(tmp);
tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
if (!access(tmp, R_OK)) {
u8 *dir = alloc_printf("%s/../lib/afl/", exepath);
obj_path = dir;
return tmp;
}
}
}
}
}
#endif
#undef HAS_PROC_FS
} }
tmp = alloc_printf("%s/%s", AFL_PATH, obj); tmp = alloc_printf("%s/%s", AFL_PATH, obj);
#ifdef __ANDROID__
if (!access(tmp, R_OK)) {
#else
if (!access(tmp, R_OK)) { if (!access(tmp, R_OK)) {
#endif
obj_path = AFL_PATH; obj_path = AFL_PATH;
return tmp; return tmp;
} }
ck_free(tmp); ck_free(tmp);
tmp = alloc_printf("./%s", obj);
if (!access(tmp, R_OK)) {
obj_path = ".";
return tmp;
}
ck_free(tmp);
return NULL; return NULL;
} }
/* Try to find the runtime libraries. If that fails, abort. */
static void find_obj(u8 *argv0) {
u8 *afl_path = getenv("AFL_PATH");
u8 *slash, *tmp;
if (afl_path) {
#ifdef __ANDROID__
tmp = alloc_printf("%s/afl-compiler-rt.so", afl_path);
#else
tmp = alloc_printf("%s/afl-compiler-rt.o", afl_path);
#endif
if (!access(tmp, R_OK)) {
obj_path = afl_path;
ck_free(tmp);
return;
}
ck_free(tmp);
}
slash = strrchr(argv0, '/');
if (slash) {
u8 *dir;
*slash = 0;
dir = ck_strdup(argv0);
*slash = '/';
#ifdef __ANDROID__
tmp = alloc_printf("%s/afl-compiler-rt.so", dir);
#else
tmp = alloc_printf("%s/afl-compiler-rt.o", dir);
#endif
if (!access(tmp, R_OK)) {
obj_path = dir;
ck_free(tmp);
return;
}
ck_free(tmp);
ck_free(dir);
}
#ifdef __ANDROID__
if (!access(AFL_PATH "/afl-compiler-rt.so", R_OK)) {
#else
if (!access(AFL_PATH "/afl-compiler-rt.o", R_OK)) {
#endif
obj_path = AFL_PATH;
return;
}
FATAL(
"Unable to find 'afl-compiler-rt.o' or 'afl-llvm-pass.so'. Please set "
"AFL_PATH");
}
/* Copy argv to cc_params, making the necessary edits. */ /* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char **argv, char **envp) { static void edit_params(u32 argc, char **argv, char **envp) {
@ -288,7 +314,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (compiler_mode >= GCC_PLUGIN) { if (compiler_mode >= GCC_PLUGIN) {
alt_cxx = "g++"; if (compiler_mode == GCC) {
alt_cxx = clang_mode ? "clang++" : "g++";
} else {
alt_cxx = "g++";
}
} else { } else {
@ -313,7 +347,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (compiler_mode >= GCC_PLUGIN) { if (compiler_mode >= GCC_PLUGIN) {
alt_cc = "gcc"; if (compiler_mode == GCC) {
alt_cc = clang_mode ? "clang" : "gcc";
} else {
alt_cc = "gcc";
}
} else { } else {
@ -337,12 +379,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = "-B"; cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = obj_path; cc_params[cc_par_cnt++] = obj_path;
if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; }
} }
if (compiler_mode == GCC_PLUGIN) { if (compiler_mode == GCC_PLUGIN) {
char *fplugin_arg = char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
alloc_printf("-fplugin=%s", find_object("afl-gcc-pass.so", argvnull));
cc_params[cc_par_cnt++] = fplugin_arg; cc_params[cc_par_cnt++] = fplugin_arg;
} }
@ -354,19 +397,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode && plusplus_mode) if (lto_mode && plusplus_mode)
cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early
if (lto_mode) { if (lto_mode && have_instr_env) {
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || cc_params[cc_par_cnt++] = "-Xclang";
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || cc_params[cc_par_cnt++] = "-load";
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
cc_params[cc_par_cnt++] = "-Xclang"; alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path);
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path);
}
} }
@ -508,11 +545,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (instrument_mode == INSTRUMENT_PCGUARD) { if (instrument_mode == INSTRUMENT_PCGUARD) {
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
cc_params[cc_par_cnt++] = "-Xclang"; if (have_instr_list) {
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang"; if (!be_quiet)
cc_params[cc_par_cnt++] = SAYF(
alloc_printf("%s/SanitizerCoveragePCGUARD.so", obj_path); "Using unoptimized trace-pc-guard, due usage of "
"-fsanitize-coverage-allow/denylist, you can use "
"AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
} else {
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/SanitizerCoveragePCGUARD.so", obj_path);
}
#else #else
#if LLVM_MAJOR >= 4 #if LLVM_MAJOR >= 4
if (!be_quiet) if (!be_quiet)
@ -590,6 +641,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
if (!strcmp(cur, "-m64")) bit_mode = 64; if (!strcmp(cur, "-m64")) bit_mode = 64;
if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list="))
have_instr_list = 1;
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
asan_set = 1; asan_set = 1;
@ -675,7 +729,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} }
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") || if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
getenv("LAF_TRANSFORM_COMPARES") || lto_mode) { getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_ALL") ||
lto_mode) {
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
@ -826,7 +881,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} }
#ifndef __APPLE__ #if !defined(__APPLE__) && !defined(__sun)
if (!shared_linking) if (!shared_linking)
cc_params[cc_par_cnt++] = cc_params[cc_par_cnt++] =
alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
@ -856,6 +911,14 @@ int main(int argc, char **argv, char **envp) {
be_quiet = 1; be_quiet = 1;
if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
getenv("AFL_LLVM_BLOCKLIST")) {
have_instr_env = 1;
}
if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1; if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
argvnull = (u8 *)argv[0]; argvnull = (u8 *)argv[0];
check_environment_vars(envp); check_environment_vars(envp);
@ -915,7 +978,9 @@ int main(int argc, char **argv, char **envp) {
} else if (strncmp(callname, "afl-gcc", 7) == 0 || } else if (strncmp(callname, "afl-gcc", 7) == 0 ||
strncmp(callname, "afl-g++", 7) == 0) { strncmp(callname, "afl-g++", 7) == 0 ||
strncmp(callname, "afl-clang", 9) == 0) {
compiler_mode = GCC; compiler_mode = GCC;
@ -959,6 +1024,14 @@ int main(int argc, char **argv, char **envp) {
} }
if (strncmp(callname, "afl-clang", 9) == 0) {
clang_mode = 1;
if (strncmp(callname, "afl-clang++", 11) == 0) { plusplus_mode = 1; }
}
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strncmp(argv[i], "--afl", 5) == 0) { if (strncmp(argv[i], "--afl", 5) == 0) {
@ -1011,26 +1084,25 @@ int main(int argc, char **argv, char **envp) {
if (instrument_mode == 0) if (instrument_mode == 0)
instrument_mode = INSTRUMENT_PCGUARD; instrument_mode = INSTRUMENT_PCGUARD;
else if (instrument_mode != INSTRUMENT_PCGUARD) else if (instrument_mode != INSTRUMENT_PCGUARD)
FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together"); FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
} }
if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || if (have_instr_env && getenv("AFL_DONT_OPTIMIZE")) {
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) &&
getenv("AFL_DONT_OPTIMIZE"))
WARNF( WARNF(
"AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined " "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
"for file matching, only function matching!"); "for file matching, only function matching!");
}
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
getenv("INSTRIM_LIB")) { getenv("INSTRIM_LIB")) {
if (instrument_mode == 0) if (instrument_mode == 0)
instrument_mode = INSTRUMENT_CFG; instrument_mode = INSTRUMENT_CFG;
else if (instrument_mode != INSTRUMENT_CFG) else if (instrument_mode != INSTRUMENT_CFG)
FATAL( FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
} }
@ -1307,15 +1379,20 @@ int main(int argc, char **argv, char **envp) {
" AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by " " AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
"filename\n"); "filename\n");
#if LLVM_MAJOR < 9
#define COUNTER_BEHAVIOUR \
" AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
#else
#define COUNTER_BEHAVIOUR \
" AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
#endif
if (have_llvm) if (have_llvm)
SAYF( SAYF(
"\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
"variables:\n" "variables:\n"
#if LLVM_MAJOR < 9
" AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n" COUNTER_BEHAVIOUR
#else
" AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
#endif
" AFL_LLVM_DICT2FILE: generate an afl dictionary based on found " " AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
"comparisons\n" "comparisons\n"
" AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n" " AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
@ -1426,22 +1503,20 @@ int main(int argc, char **argv, char **envp) {
#if LLVM_MAJOR <= 6 #if LLVM_MAJOR <= 6
instrument_mode = INSTRUMENT_AFL; instrument_mode = INSTRUMENT_AFL;
#else #else
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || if (have_instr_env) {
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
instrument_mode = INSTRUMENT_AFL; instrument_mode = INSTRUMENT_AFL;
WARNF( if (!be_quiet)
"switching to classic instrumentation because " WARNF(
"AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use " "Switching to classic instrumentation because "
"-fsanitize-coverage-allowlist=allowlist.txt or " "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
"-fsanitize-coverage-blocklist=denylist.txt if you want to use "
"PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ "
"SanitizerCoverage.html#partially-disabling-instrumentation");
} else } else
#endif
instrument_mode = INSTRUMENT_PCGUARD; instrument_mode = INSTRUMENT_PCGUARD;
#endif #endif
} }
@ -1487,18 +1562,16 @@ int main(int argc, char **argv, char **envp) {
"AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set " "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
"together"); "together");
if (instrument_mode == INSTRUMENT_PCGUARD && #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
(getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || if (instrument_mode == INSTRUMENT_PCGUARD && have_instr_env) {
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")))
FATAL( FATAL(
"Instrumentation type PCGUARD does not support " "Instrumentation type PCGUARD does not support "
"AFL_LLVM_ALLOWLIST/DENYLIST! Use " "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
"-fsanitize-coverage-allowlist=allowlist.txt or "
"-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm " }
"12+), see "
"https://clang.llvm.org/docs/" #endif
"SanitizerCoverage.html#partially-disabling-instrumentation");
u8 *ptr2; u8 *ptr2;
@ -1525,7 +1598,7 @@ int main(int argc, char **argv, char **envp) {
if (debug) { if (debug) {
SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd()); DEBUGF("cd '%s';", getthecwd());
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
SAYF(" '%s'", argv[i]); SAYF(" '%s'", argv[i]);
SAYF("\n"); SAYF("\n");
@ -1545,15 +1618,29 @@ int main(int argc, char **argv, char **envp) {
if (!be_quiet && cmplog_mode) if (!be_quiet && cmplog_mode)
printf("CmpLog mode by <andreafioraldi@gmail.com>\n"); printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
#ifndef __ANDROID__ #ifdef __ANDROID__
find_obj(argv[0]); ptr = find_object("afl-compiler-rt.so", argv[0]);
#else
ptr = find_object("afl-compiler-rt.o", argv[0]);
#endif #endif
if (!ptr) {
FATAL(
"Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
"environment variable.");
}
if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); }
ck_free(ptr);
edit_params(argc, argv, envp); edit_params(argc, argv, envp);
if (debug) { if (debug) {
SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd()); DEBUGF("cd '%s';", getthecwd());
for (i = 0; i < (s32)cc_par_cnt; i++) for (i = 0; i < (s32)cc_par_cnt; i++)
SAYF(" '%s'", cc_params[i]); SAYF(" '%s'", cc_params[i]);
SAYF("\n"); SAYF("\n");

View File

@ -46,7 +46,7 @@ u8 be_quiet = 0;
u8 *doc_path = ""; u8 *doc_path = "";
u8 last_intr = 0; u8 last_intr = 0;
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) {
u32 i = 0; u32 i = 0;
u8 cwd[PATH_MAX]; u8 cwd[PATH_MAX];
@ -63,7 +63,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); } if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); }
*use_stdin = 0; *use_stdin = false;
if (prog_in[0] != 0) { // not afl-showmap special case if (prog_in[0] != 0) { // not afl-showmap special case

View File

@ -62,6 +62,7 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
execv(fsrv->target_path, argv); execv(fsrv->target_path, argv);
WARNF("Execv failed in forkserver.");
} }
/* Initializes the struct */ /* Initializes the struct */
@ -76,8 +77,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->dev_urandom_fd = -1; fsrv->dev_urandom_fd = -1;
/* Settings */ /* Settings */
fsrv->use_stdin = 1; fsrv->use_stdin = true;
fsrv->no_unlink = 0; fsrv->no_unlink = false;
fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->exec_tmout = EXEC_TIMEOUT;
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
fsrv->mem_limit = MEM_LIMIT; fsrv->mem_limit = MEM_LIMIT;
@ -86,8 +87,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
/* exec related stuff */ /* exec related stuff */
fsrv->child_pid = -1; fsrv->child_pid = -1;
fsrv->map_size = get_map_size(); fsrv->map_size = get_map_size();
fsrv->use_fauxsrv = 0; fsrv->use_fauxsrv = false;
fsrv->last_run_timed_out = 0; fsrv->last_run_timed_out = false;
fsrv->uses_crash_exitcode = false;
fsrv->uses_asan = false;
fsrv->init_child_func = fsrv_exec_child; fsrv->init_child_func = fsrv_exec_child;
@ -109,6 +113,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->dev_urandom_fd = from->dev_urandom_fd; fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
fsrv_to->out_fd = from->out_fd; // not sure this is a good idea fsrv_to->out_fd = from->out_fd; // not sure this is a good idea
fsrv_to->no_unlink = from->no_unlink; fsrv_to->no_unlink = from->no_unlink;
fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
fsrv_to->crash_exitcode = from->crash_exitcode;
// These are forkserver specific. // These are forkserver specific.
fsrv_to->out_dir_fd = -1; fsrv_to->out_dir_fd = -1;
@ -116,7 +122,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->use_fauxsrv = 0; fsrv_to->use_fauxsrv = 0;
fsrv_to->last_run_timed_out = 0; fsrv_to->last_run_timed_out = 0;
fsrv_to->init_child_func = fsrv_exec_child; fsrv_to->init_child_func = from->init_child_func;
// Note: do not copy ->add_extra_func // Note: do not copy ->add_extra_func
list_append(&fsrv_list, fsrv_to); list_append(&fsrv_list, fsrv_to);
@ -272,7 +278,8 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
*(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG; *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
PFATAL("Execv failed in fauxserver."); WARNF("Execv failed in fauxserver.");
break;
} }
@ -286,13 +293,13 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
if (waitpid(child_pid, &status, 0) < 0) { if (waitpid(child_pid, &status, 0) < 0) {
// Zombie Child could not be collected. Scary! // Zombie Child could not be collected. Scary!
PFATAL("Fauxserver could not determin child's exit code. "); WARNF("Fauxserver could not determine child's exit code. ");
} }
/* Relay wait status to AFL pipe, then loop back. */ /* Relay wait status to AFL pipe, then loop back. */
if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(0); } if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(1); }
} }
@ -330,7 +337,7 @@ static void report_error_and_exit(int error) {
"memory failed."); "memory failed.");
break; break;
default: default:
FATAL("unknown error code %u from fuzzing target!", error); FATAL("unknown error code %d from fuzzing target!", error);
} }
@ -347,15 +354,16 @@ static void report_error_and_exit(int error) {
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) { volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2]; int st_pipe[2], ctl_pipe[2];
s32 status; s32 status;
s32 rlen; s32 rlen;
char *ignore_autodict = getenv("AFL_NO_AUTODICT");
if (!be_quiet) { ACTF("Spinning up the fork server..."); } if (!be_quiet) { ACTF("Spinning up the fork server..."); }
if (fsrv->use_fauxsrv) { if (fsrv->use_fauxsrv) {
/* TODO: Come up with sone nice way to initialize this all */ /* TODO: Come up with some nice way to initialize this all */
if (fsrv->init_child_func != fsrv_exec_child) { if (fsrv->init_child_func != fsrv_exec_child) {
@ -519,8 +527,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
falling through. */ falling through. */
*(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG; *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
fprintf(stderr, "Error: execv to target failed\n"); FATAL("Error: execv to target failed\n");
exit(0);
} }
@ -606,7 +613,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
fsrv->use_shmem_fuzz = 1; fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0) { if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
@ -659,16 +666,44 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { if (ignore_autodict) {
if (!be_quiet) { WARNF("Ignoring offered AUTODICT feature."); }
} else {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
return;
}
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) { if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else { } else {
status = (FS_OPT_ENABLED); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
} }
@ -678,82 +713,62 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} }
return; if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
} FATAL("Reading from forkserver failed.");
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
FATAL("Reading from forkserver failed.");
}
if (status < 2 || (u32)status > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", status);
}
u32 offset = 0, count = 0;
u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory", len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
} }
} if (status < 2 || (u32)status > 0xffffff) {
offset = 0; FATAL("Dictionary has an illegal size: %d", status);
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, }
(u8)dict[offset]);
offset += (1 + dict[offset]); u32 offset = 0, count = 0;
count++; u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory", len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
}
}
offset = 0;
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
} }
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
} }
} }
@ -901,7 +916,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" estimate the required amount of virtual memory for the " " estimate the required amount of virtual memory for the "
"binary.\n\n" "binary.\n\n"
" - the target was compiled with afl-clang-lto and a constructor " " - The target was compiled with afl-clang-lto and a constructor "
"was\n" "was\n"
" instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve " " instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
"your \n" "your \n"
@ -1054,6 +1069,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (fsrv->child_pid <= 0) { if (fsrv->child_pid <= 0) {
if (*stop_soon_p) { return 0; } if (*stop_soon_p) { return 0; }
if ((fsrv->child_pid & FS_OPT_ERROR) &&
FS_OPT_GET_ERROR(fsrv->child_pid) == FS_ERROR_SHM_OPEN)
FATAL(
"Target reported shared memory access failed (perhaps increase "
"shared memory available).");
FATAL("Fork server is misbehaving (OOM?)"); FATAL("Fork server is misbehaving (OOM?)");
} }
@ -1126,10 +1148,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
} }
/* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and /* MSAN in uses_asan mode uses a special exit code as it doesn't support
must use a special exit code. */ abort_on_error.
On top, a user may specify a custom AFL_CRASH_EXITCODE. Handle both here. */
if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) { if ((fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
(fsrv->uses_crash_exitcode &&
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) {
fsrv->last_kill_signal = 0; fsrv->last_kill_signal = 0;
return FSRV_RUN_CRASH; return FSRV_RUN_CRASH;
@ -1137,7 +1162,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
} }
// Fauxserver should handle this now. // Fauxserver should handle this now.
// if (tb4 == EXEC_FAIL_SIG) return FSRV_RUN_ERROR; if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) return FSRV_RUN_ERROR;
return FSRV_RUN_OK; return FSRV_RUN_OK;

View File

@ -425,8 +425,10 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
/* Construct a file name for a new test case, capturing the operation /* Construct a file name for a new test case, capturing the operation
that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */ that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */
u8 *describe_op(afl_state_t *afl, u8 hnb) { u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
size_t real_max_len =
MIN(max_description_len, sizeof(afl->describe_op_buf_256));
u8 *ret = afl->describe_op_buf_256; u8 *ret = afl->describe_op_buf_256;
if (unlikely(afl->syncing_party)) { if (unlikely(afl->syncing_party)) {
@ -445,29 +447,66 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time); sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
sprintf(ret + strlen(ret), ",op:%s", afl->stage_short); if (afl->current_custom_fuzz &&
afl->current_custom_fuzz->afl_custom_describe) {
if (afl->stage_cur_byte >= 0) { /* We are currently in a custom mutator that supports afl_custom_describe,
* use it! */
sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte); size_t len_current = strlen(ret);
ret[len_current++] = ',';
ret[len_current] = '\0';
if (afl->stage_val_type != STAGE_VAL_NONE) { ssize_t size_left = real_max_len - len_current - strlen(",+cov") - 2;
if (unlikely(size_left <= 0)) FATAL("filename got too long");
sprintf(ret + strlen(ret), ",val:%s%+d", const char *custom_description =
(afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "", afl->current_custom_fuzz->afl_custom_describe(
afl->stage_cur_val); afl->current_custom_fuzz->data, size_left);
if (!custom_description || !custom_description[0]) {
DEBUGF("Error getting a description from afl_custom_describe");
/* Take the stage name as description fallback */
sprintf(ret + len_current, "op:%s", afl->stage_short);
} else {
/* We got a proper custom description, use it */
strncat(ret + len_current, custom_description, size_left);
} }
} else { } else {
sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val); /* Normal testcase descriptions start here */
sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
if (afl->stage_cur_byte >= 0) {
sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte);
if (afl->stage_val_type != STAGE_VAL_NONE) {
sprintf(ret + strlen(ret), ",val:%s%+d",
(afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "",
afl->stage_cur_val);
}
} else {
sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val);
}
} }
} }
if (hnb == 2) { strcat(ret, ",+cov"); } if (new_bits == 2) { strcat(ret, ",+cov"); }
if (unlikely(strlen(ret) >= max_description_len))
FATAL("describe string is too long");
return ret; return ret;
@ -540,7 +579,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(len == 0)) { return 0; } if (unlikely(len == 0)) { return 0; }
u8 *queue_fn = ""; u8 *queue_fn = "";
u8 hnb = '\0'; u8 new_bits = '\0';
s32 fd; s32 fd;
u8 keeping = 0, res; u8 keeping = 0, res;
u64 cksum = 0; u64 cksum = 0;
@ -566,7 +605,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* Keep only if there are new bits in the map, add to queue for /* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */ future fuzzing, etc. */
if (!(hnb = has_new_bits(afl, afl->virgin_bits))) { if (!(new_bits = has_new_bits(afl, afl->virgin_bits))) {
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; } if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
return 0; return 0;
@ -575,8 +614,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, queue_fn = alloc_printf(
afl->queued_paths, describe_op(afl, hnb)); "%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths,
describe_op(afl, new_bits, NAME_MAX - strlen("id:000000,")));
#else #else
@ -584,7 +624,10 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths); alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths);
#endif /* ^!SIMPLE_FILES */ #endif /* ^!SIMPLE_FILES */
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
ck_write(fd, mem, len, queue_fn);
close(fd);
add_to_queue(afl, queue_fn, len, 0); add_to_queue(afl, queue_fn, len, 0);
#ifdef INTROSPECTION #ifdef INTROSPECTION
@ -616,7 +659,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#endif #endif
if (hnb == 2) { if (new_bits == 2) {
afl->queue_top->has_new_cov = 1; afl->queue_top->has_new_cov = 1;
++afl->queued_with_cov; ++afl->queued_with_cov;
@ -647,11 +690,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
} }
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
ck_write(fd, mem, len, queue_fn);
close(fd);
if (likely(afl->q_testcase_max_cache_size)) { if (likely(afl->q_testcase_max_cache_size)) {
queue_testcase_store_mem(afl, afl->queue_top, mem); queue_testcase_store_mem(afl, afl->queue_top, mem);
@ -744,7 +782,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir, snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir,
afl->unique_hangs, describe_op(afl, 0)); afl->unique_hangs,
describe_op(afl, 0, NAME_MAX - strlen("id:000000,")));
#else #else
@ -789,7 +828,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
afl->unique_crashes, afl->fsrv.last_kill_signal, afl->unique_crashes, afl->fsrv.last_kill_signal,
describe_op(afl, 0)); describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")));
#else #else

View File

@ -355,7 +355,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used); if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used);
for (i = 0; i < ncpus; i++) { for (i = 0; i < (s32)ncpus; i++) {
k = kstat_lookup(m, "cpu_stat", i, NULL); k = kstat_lookup(m, "cpu_stat", i, NULL);
if (kstat_read(m, k, &cs)) { if (kstat_read(m, k, &cs)) {
@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) {
if (skip_crashes) { if (skip_crashes) {
WARNF("Test case results in a crash (skipping)"); if (afl->fsrv.uses_crash_exitcode) {
WARNF(
"Test case results in a crash or AFL_CRASH_EXITCODE %d "
"(skipping)",
(int)(s8)afl->fsrv.crash_exitcode);
} else {
WARNF("Test case results in a crash (skipping)");
}
q->cal_failed = CAL_CHANCES; q->cal_failed = CAL_CHANCES;
++cal_failures; ++cal_failures;
break; break;
@ -954,7 +966,18 @@ void perform_dry_run(afl_state_t *afl) {
#undef MSG_ULIMIT_USAGE #undef MSG_ULIMIT_USAGE
#undef MSG_FORK_ON_APPLE #undef MSG_FORK_ON_APPLE
WARNF("Test case '%s' results in a crash, skipping", fn); if (afl->fsrv.uses_crash_exitcode) {
WARNF(
"Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, "
"skipping",
fn, (int)(s8)afl->fsrv.crash_exitcode);
} else {
WARNF("Test case '%s' results in a crash, skipping", fn);
}
/* Remove from fuzzing queue but keep for splicing */ /* Remove from fuzzing queue but keep for splicing */
@ -2300,12 +2323,6 @@ void fix_up_sync(afl_state_t *afl) {
u8 *x = afl->sync_id; u8 *x = afl->sync_id;
if (afl->non_instrumented_mode) {
FATAL("-S / -M and -n are mutually exclusive");
}
while (*x) { while (*x) {
if (!isalnum(*x) && *x != '_' && *x != '-') { if (!isalnum(*x) && *x != '_' && *x != '-') {
@ -2503,7 +2520,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
} }
if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode) { if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
afl->non_instrumented_mode) {
return; return;

View File

@ -151,7 +151,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
/* Mutator */ /* Mutator */
/* "afl_custom_init", optional for backward compatibility */ /* "afl_custom_init", optional for backward compatibility */
mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
if (!mutator->afl_custom_init) FATAL("Symbol 'afl_custom_init' not found."); if (!mutator->afl_custom_init) {
FATAL("Symbol 'afl_custom_init' not found.");
}
/* "afl_custom_fuzz" or "afl_custom_mutator", required */ /* "afl_custom_fuzz" or "afl_custom_mutator", required */
mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
@ -161,49 +165,74 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'."); WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator"); mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
if (!mutator->afl_custom_fuzz) if (!mutator->afl_custom_fuzz) {
WARNF("Symbol 'afl_custom_mutator' not found."); WARNF("Symbol 'afl_custom_mutator' not found.");
}
} }
/* "afl_custom_introspection", optional */ /* "afl_custom_introspection", optional */
#ifdef INTROSPECTION #ifdef INTROSPECTION
mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection"); mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
if (!mutator->afl_custom_introspection) if (!mutator->afl_custom_introspection) {
ACTF("optional symbol 'afl_custom_introspection' not found."); ACTF("optional symbol 'afl_custom_introspection' not found.");
}
#endif #endif
/* "afl_custom_fuzz_count", optional */ /* "afl_custom_fuzz_count", optional */
mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count"); mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
if (!mutator->afl_custom_fuzz_count) if (!mutator->afl_custom_fuzz_count) {
ACTF("optional symbol 'afl_custom_fuzz_count' not found."); ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
}
/* "afl_custom_deinit", optional for backward compatibility */ /* "afl_custom_deinit", optional for backward compatibility */
mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
if (!mutator->afl_custom_deinit) if (!mutator->afl_custom_deinit) {
FATAL("Symbol 'afl_custom_deinit' not found."); FATAL("Symbol 'afl_custom_deinit' not found.");
}
/* "afl_custom_post_process", optional */ /* "afl_custom_post_process", optional */
mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process"); mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
if (!mutator->afl_custom_post_process) if (!mutator->afl_custom_post_process) {
ACTF("optional symbol 'afl_custom_post_process' not found."); ACTF("optional symbol 'afl_custom_post_process' not found.");
}
u8 notrim = 0; u8 notrim = 0;
/* "afl_custom_init_trim", optional */ /* "afl_custom_init_trim", optional */
mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
if (!mutator->afl_custom_init_trim) if (!mutator->afl_custom_init_trim) {
ACTF("optional symbol 'afl_custom_init_trim' not found."); ACTF("optional symbol 'afl_custom_init_trim' not found.");
}
/* "afl_custom_trim", optional */ /* "afl_custom_trim", optional */
mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim"); mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
if (!mutator->afl_custom_trim) if (!mutator->afl_custom_trim) {
ACTF("optional symbol 'afl_custom_trim' not found."); ACTF("optional symbol 'afl_custom_trim' not found.");
}
/* "afl_custom_post_trim", optional */ /* "afl_custom_post_trim", optional */
mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim"); mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
if (!mutator->afl_custom_post_trim) if (!mutator->afl_custom_post_trim) {
ACTF("optional symbol 'afl_custom_post_trim' not found."); ACTF("optional symbol 'afl_custom_post_trim' not found.");
}
if (notrim) { if (notrim) {
mutator->afl_custom_init_trim = NULL; mutator->afl_custom_init_trim = NULL;
@ -217,31 +246,54 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
/* "afl_custom_havoc_mutation", optional */ /* "afl_custom_havoc_mutation", optional */
mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation"); mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
if (!mutator->afl_custom_havoc_mutation) if (!mutator->afl_custom_havoc_mutation) {
ACTF("optional symbol 'afl_custom_havoc_mutation' not found."); ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
}
/* "afl_custom_havoc_mutation", optional */ /* "afl_custom_havoc_mutation", optional */
mutator->afl_custom_havoc_mutation_probability = mutator->afl_custom_havoc_mutation_probability =
dlsym(dh, "afl_custom_havoc_mutation_probability"); dlsym(dh, "afl_custom_havoc_mutation_probability");
if (!mutator->afl_custom_havoc_mutation_probability) if (!mutator->afl_custom_havoc_mutation_probability) {
ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found."); ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
}
/* "afl_custom_queue_get", optional */ /* "afl_custom_queue_get", optional */
mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get"); mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
if (!mutator->afl_custom_queue_get) if (!mutator->afl_custom_queue_get) {
ACTF("optional symbol 'afl_custom_queue_get' not found."); ACTF("optional symbol 'afl_custom_queue_get' not found.");
}
/* "afl_custom_queue_new_entry", optional */ /* "afl_custom_queue_new_entry", optional */
mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry"); mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
if (!mutator->afl_custom_queue_new_entry) if (!mutator->afl_custom_queue_new_entry) {
ACTF("optional symbol 'afl_custom_queue_new_entry' not found"); ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
}
/* "afl_custom_describe", optional */
mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
if (!mutator->afl_custom_describe) {
ACTF("Symbol 'afl_custom_describe' not found.");
}
OKF("Custom mutator '%s' installed successfully.", fn); OKF("Custom mutator '%s' installed successfully.", fn);
/* Initialize the custom mutator */ /* Initialize the custom mutator */
if (mutator->afl_custom_init) if (mutator->afl_custom_init) {
mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
}
mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation); mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
mutator->stacked_custom_prob = mutator->stacked_custom_prob =
6; // like one of the default mutations in havoc 6; // like one of the default mutations in havoc

View File

@ -445,8 +445,13 @@ u8 fuzz_one_original(afl_state_t *afl) {
if (unlikely(afl->not_on_tty)) { if (unlikely(afl->not_on_tty)) {
ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...", ACTF(
afl->current_entry, afl->queued_paths, afl->unique_crashes); "Fuzzing test case #%u (%u total, %llu uniq crashes found, "
"perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...",
afl->current_entry, afl->queued_paths, afl->unique_crashes,
afl->queue_cur->perf_score, afl->queue_cur->exec_us,
likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
afl->queue_cur->bitmap_size);
fflush(stdout); fflush(stdout);
} }
@ -1790,11 +1795,16 @@ custom_mutator_stage:
afl->current_custom_fuzz = el; afl->current_custom_fuzz = el;
if (el->afl_custom_fuzz_count) if (el->afl_custom_fuzz_count) {
afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len); afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
else
} else {
afl->stage_max = saved_max; afl->stage_max = saved_max;
}
has_custom_fuzz = true; has_custom_fuzz = true;
afl->stage_short = el->name_short; afl->stage_short = el->name_short;

View File

@ -96,7 +96,7 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
mutated_size = PyByteArray_Size(py_value); mutated_size = PyByteArray_Size(py_value);
*out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size); *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
if (unlikely(!out_buf)) { PFATAL("alloc"); } if (unlikely(!*out_buf)) { PFATAL("alloc"); }
memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
Py_DECREF(py_value); Py_DECREF(py_value);
@ -111,6 +111,37 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
} }
static const char *custom_describe_py(void * py_mutator,
size_t max_description_len) {
PyObject *py_args, *py_value;
py_args = PyTuple_New(1);
PyLong_FromSize_t(max_description_len);
/* add_buf */
py_value = PyLong_FromSize_t(max_description_len);
if (!py_value) {
Py_DECREF(py_args);
FATAL("Failed to convert arguments");
}
PyTuple_SetItem(py_args, 0, py_value);
py_value = PyObject_CallObject(
((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DESCRIBE], py_args);
Py_DECREF(py_args);
if (py_value != NULL) { return PyBytes_AsString(py_value); }
return NULL;
}
static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
(void)afl; (void)afl;
@ -134,6 +165,18 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject * py_module = py->py_module; PyObject * py_module = py->py_module;
PyObject **py_functions = py->py_functions; PyObject **py_functions = py->py_functions;
// initialize the post process buffer; ensures it's always valid
PyObject *unused_bytes = PyByteArray_FromStringAndSize("OHAI", 4);
if (!unused_bytes) { FATAL("allocation failed!"); }
if (PyObject_GetBuffer(unused_bytes, &py->post_process_buf, PyBUF_SIMPLE) ==
-1) {
FATAL("buffer initialization failed");
}
Py_DECREF(unused_bytes);
if (py_module != NULL) { if (py_module != NULL) {
u8 py_notrim = 0, py_idx; u8 py_notrim = 0, py_idx;
@ -144,6 +187,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
if (!py_functions[PY_FUNC_FUZZ]) if (!py_functions[PY_FUNC_FUZZ])
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate"); py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
py_functions[PY_FUNC_DESCRIBE] =
PyObject_GetAttrString(py_module, "describe");
py_functions[PY_FUNC_FUZZ_COUNT] = py_functions[PY_FUNC_FUZZ_COUNT] =
PyObject_GetAttrString(py_module, "fuzz_count"); PyObject_GetAttrString(py_module, "fuzz_count");
if (!py_functions[PY_FUNC_FUZZ]) if (!py_functions[PY_FUNC_FUZZ])
@ -313,7 +358,6 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
struct custom_mutator *mutator; struct custom_mutator *mutator;
mutator = ck_alloc(sizeof(struct custom_mutator)); mutator = ck_alloc(sizeof(struct custom_mutator));
mutator->post_process_buf = NULL;
mutator->name = module_name; mutator->name = module_name;
ACTF("Loading Python mutator library from '%s'...", module_name); ACTF("Loading Python mutator library from '%s'...", module_name);
@ -329,9 +373,13 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
if (py_functions[PY_FUNC_DEINIT]) { mutator->afl_custom_deinit = deinit_py; } if (py_functions[PY_FUNC_DEINIT]) { mutator->afl_custom_deinit = deinit_py; }
/* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator if (py_functions[PY_FUNC_FUZZ]) { mutator->afl_custom_fuzz = fuzz_py; }
is quite different from the custom mutator. */
mutator->afl_custom_fuzz = fuzz_py; if (py_functions[PY_FUNC_DESCRIBE]) {
mutator->afl_custom_describe = custom_describe_py;
}
if (py_functions[PY_FUNC_POST_PROCESS]) { if (py_functions[PY_FUNC_POST_PROCESS]) {
@ -405,10 +453,13 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size, size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
u8 **out_buf) { u8 **out_buf) {
size_t py_out_buf_size;
PyObject * py_args, *py_value; PyObject * py_args, *py_value;
py_mutator_t *py = (py_mutator_t *)py_mutator; py_mutator_t *py = (py_mutator_t *)py_mutator;
// buffer returned previously must be released; initialized during init
// so we don't need to do comparisons
PyBuffer_Release(&py->post_process_buf);
py_args = PyTuple_New(1); py_args = PyTuple_New(1);
py_value = PyByteArray_FromStringAndSize(buf, buf_size); py_value = PyByteArray_FromStringAndSize(buf, buf_size);
if (!py_value) { if (!py_value) {
@ -428,20 +479,20 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
if (py_value != NULL) { if (py_value != NULL) {
py_out_buf_size = PyByteArray_Size(py_value); if (PyObject_GetBuffer(py_value, &py->post_process_buf, PyBUF_SIMPLE) ==
-1) {
if (unlikely(!afl_realloc(BUF_PARAMS(post_process), py_out_buf_size))) { PyErr_Print();
FATAL(
PFATAL("alloc"); "Python custom mutator: post_process call return value not a "
"bytes-like object");
} }
memcpy(py->post_process_buf, PyByteArray_AsString(py_value),
py_out_buf_size);
Py_DECREF(py_value); Py_DECREF(py_value);
*out_buf = py->post_process_buf; *out_buf = (u8 *)py->post_process_buf.buf;
return py_out_buf_size; return py->post_process_buf.len;
} else { } else {
@ -581,7 +632,7 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
ret = PyByteArray_Size(py_value); ret = PyByteArray_Size(py_value);
*out_buf = afl_realloc(BUF_PARAMS(trim), ret); *out_buf = afl_realloc(BUF_PARAMS(trim), ret);
if (unlikely(!out_buf)) { PFATAL("alloc"); } if (unlikely(!*out_buf)) { PFATAL("alloc"); }
memcpy(*out_buf, PyByteArray_AsString(py_value), ret); memcpy(*out_buf, PyByteArray_AsString(py_value), ret);
Py_DECREF(py_value); Py_DECREF(py_value);
@ -647,7 +698,7 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
/* A new buf is needed... */ /* A new buf is needed... */
*out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size); *out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size);
if (unlikely(!out_buf)) { PFATAL("alloc"); } if (unlikely(!*out_buf)) { PFATAL("alloc"); }
} }

View File

@ -42,11 +42,29 @@ inline u32 select_next_queue_entry(afl_state_t *afl) {
} }
double compute_weight(afl_state_t *afl, struct queue_entry *q,
double avg_exec_us, double avg_bitmap_size) {
u32 hits = afl->n_fuzz[q->n_fuzz_entry];
if (hits == 0) hits = 1;
double weight = 1.0;
weight *= avg_exec_us / q->exec_us;
weight *= log(q->bitmap_size) / avg_bitmap_size;
weight /= log10(hits) + 1;
if (q->favored) weight *= 5;
return weight;
}
/* create the alias table that allows weighted random selection - expensive */ /* create the alias table that allows weighted random selection - expensive */
void create_alias_table(afl_state_t *afl) { void create_alias_table(afl_state_t *afl) {
u32 n = afl->queued_paths, i = 0, a, g; u32 n = afl->queued_paths, i = 0, a, g;
double sum = 0;
afl->alias_table = afl->alias_table =
(u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32)); (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
@ -56,26 +74,69 @@ void create_alias_table(afl_state_t *afl) {
int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32)); int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32)); int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
if (!P || !S || !L) { FATAL("could not aquire memory for alias table"); } if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
memset((void *)afl->alias_table, 0, n * sizeof(u32));
memset((void *)afl->alias_probability, 0, n * sizeof(double));
double sum = 0; FATAL("could not acquire memory for alias table");
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
if (!q->disabled) { q->perf_score = calculate_score(afl, q); }
sum += q->perf_score;
} }
for (i = 0; i < n; i++) { memset((void *)afl->alias_table, 0, n * sizeof(u32));
memset((void *)afl->alias_probability, 0, n * sizeof(double));
struct queue_entry *q = afl->queue_buf[i]; if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
P[i] = (q->perf_score * n) / sum;
double avg_exec_us = 0.0;
double avg_bitmap_size = 0.0;
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
avg_exec_us += q->exec_us;
avg_bitmap_size += log(q->bitmap_size);
}
avg_exec_us /= afl->queued_paths;
avg_bitmap_size /= afl->queued_paths;
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
if (!q->disabled) {
q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size);
q->perf_score = calculate_score(afl, q);
}
sum += q->weight;
}
for (i = 0; i < n; i++) {
P[i] = (afl->queue_buf[i]->weight * n) / sum;
}
} else {
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
if (!q->disabled) { q->perf_score = calculate_score(afl, q); }
sum += q->perf_score;
}
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
P[i] = (q->perf_score * n) / sum;
}
} }

View File

@ -79,7 +79,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
s32 doc_fd; s32 doc_fd;
char fn[PATH_MAX]; char fn[PATH_MAX];
snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir, snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
afl->document_counter++, describe_op(afl, 0)); afl->document_counter++,
describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) { if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
@ -332,7 +333,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
} }
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child_output); afl->afl_env.afl_debug_child);
if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) { if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
@ -484,7 +485,7 @@ void sync_fuzzers(afl_state_t *afl) {
DIR * sd; DIR * sd;
struct dirent *sd_ent; struct dirent *sd_ent;
u32 sync_cnt = 0, synced = 0, entries = 0; u32 sync_cnt = 0, synced = 0, entries = 0;
u8 path[PATH_MAX + 256]; u8 path[PATH_MAX + 1 + NAME_MAX];
sd = opendir(afl->sync_dir); sd = opendir(afl->sync_dir);
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); } if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
@ -590,7 +591,7 @@ void sync_fuzzers(afl_state_t *afl) {
while (m < n) { while (m < n) {
if (strcmp(namelist[m]->d_name, entry)) { if (strncmp(namelist[m]->d_name, entry, 9)) {
m++; m++;

View File

@ -268,11 +268,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_bench_until_crash = afl->afl_env.afl_bench_until_crash =
get_afl_env(afl_environment_variables[i]) ? 1 : 0; get_afl_env(afl_environment_variables[i]) ? 1 : 0;
} else if (!strncmp(env, "AFL_DEBUG_CHILD_OUTPUT", } else if (!strncmp(env, "AFL_DEBUG_CHILD",
afl_environment_variable_len) ||
!strncmp(env, "AFL_DEBUG_CHILD_OUTPUT",
afl_environment_variable_len)) { afl_environment_variable_len)) {
afl->afl_env.afl_debug_child_output = afl->afl_env.afl_debug_child =
get_afl_env(afl_environment_variables[i]) ? 1 : 0; get_afl_env(afl_environment_variables[i]) ? 1 : 0;
} else if (!strncmp(env, "AFL_AUTORESUME", } else if (!strncmp(env, "AFL_AUTORESUME",
@ -392,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_statsd_tags_flavor = afl->afl_env.afl_statsd_tags_flavor =
(u8 *)get_afl_env(afl_environment_variables[i]); (u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_CRASH_EXITCODE",
afl_environment_variable_len)) {
afl->afl_env.afl_crash_exitcode =
(u8 *)get_afl_env(afl_environment_variables[i]);
} }
} else { } else {

View File

@ -26,6 +26,7 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "cmplog.h" #include "cmplog.h"
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#ifndef USEMMAP #ifndef USEMMAP
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -40,7 +41,7 @@ extern u64 time_spent_working;
static void at_exit() { static void at_exit() {
int i; s32 i, pid1 = 0, pid2 = 0;
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL}; char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
char *ptr; char *ptr;
@ -48,10 +49,10 @@ static void at_exit() {
if (ptr && *ptr) unlink(ptr); if (ptr && *ptr) unlink(ptr);
ptr = getenv("__AFL_TARGET_PID1"); ptr = getenv("__AFL_TARGET_PID1");
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); if (ptr && *ptr && (pid1 = atoi(ptr)) > 0) kill(pid1, SIGTERM);
ptr = getenv("__AFL_TARGET_PID2"); ptr = getenv("__AFL_TARGET_PID2");
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) kill(pid2, SIGTERM);
i = 0; i = 0;
while (list[i] != NULL) { while (list[i] != NULL) {
@ -75,6 +76,9 @@ static void at_exit() {
} }
if (pid1 > 0) { kill(pid1, SIGKILL); }
if (pid2 > 0) { kill(pid2, SIGKILL); }
} }
/* Display usage hints. */ /* Display usage hints. */
@ -162,11 +166,12 @@ static void usage(u8 *argv0, int more_help) {
"AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
"AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_JUST_ONE: run the target just once\n"
"AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
"AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
"AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
"AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
"AFL_DEBUG: extra debugging output for Python mode trimming\n" "AFL_DEBUG: extra debugging output for Python mode trimming\n"
"AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n" "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
"AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
"AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
"AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
@ -184,6 +189,7 @@ static void usage(u8 *argv0, int more_help) {
" used. Defaults to 200.\n" " used. Defaults to 200.\n"
"AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
"AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
"AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
"AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
"AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
@ -350,6 +356,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 's': { case 's': {
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
rand_set_seed(afl, strtoul(optarg, 0L, 10)); rand_set_seed(afl, strtoul(optarg, 0L, 10));
afl->fixed_seed = 1; afl->fixed_seed = 1;
break; break;
@ -419,6 +426,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'i': /* input dir */ case 'i': /* input dir */
if (afl->in_dir) { FATAL("Multiple -i options not supported"); } if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
afl->in_dir = optarg; afl->in_dir = optarg;
if (!strcmp(afl->in_dir, "-")) { afl->in_place_resume = 1; } if (!strcmp(afl->in_dir, "-")) { afl->in_place_resume = 1; }
@ -435,9 +443,26 @@ int main(int argc, char **argv_orig, char **envp) {
u8 *c; u8 *c;
if (afl->non_instrumented_mode) {
FATAL("-M is not supported in non-instrumented mode");
}
if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); } if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
/* sanity check for argument: should not begin with '-' (possible
* option) */
if (optarg && *optarg == '-') {
FATAL(
"argument for -M started with a dash '-', which is used for "
"options");
}
afl->sync_id = ck_strdup(optarg); afl->sync_id = ck_strdup(optarg);
afl->skip_deterministic = 0; // force determinsitic fuzzing afl->skip_deterministic = 0; // force deterministic fuzzing
afl->old_seed_selection = 1; // force old queue walking seed selection afl->old_seed_selection = 1; // force old queue walking seed selection
if ((c = strchr(afl->sync_id, ':'))) { if ((c = strchr(afl->sync_id, ':'))) {
@ -464,7 +489,24 @@ int main(int argc, char **argv_orig, char **envp) {
case 'S': /* secondary sync id */ case 'S': /* secondary sync id */
if (afl->non_instrumented_mode) {
FATAL("-S is not supported in non-instrumented mode");
}
if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); } if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
/* sanity check for argument: should not begin with '-' (possible
* option) */
if (optarg && *optarg == '-') {
FATAL(
"argument for -M started with a dash '-', which is used for "
"options");
}
afl->sync_id = ck_strdup(optarg); afl->sync_id = ck_strdup(optarg);
afl->is_secondary_node = 1; afl->is_secondary_node = 1;
break; break;
@ -620,6 +662,12 @@ int main(int argc, char **argv_orig, char **envp) {
case 'n': /* dumb mode */ case 'n': /* dumb mode */
if (afl->is_main_node || afl->is_secondary_node) {
FATAL("Non instrumented mode is not supported with -M / -S");
}
if (afl->non_instrumented_mode) { if (afl->non_instrumented_mode) {
FATAL("Multiple -n options not supported"); FATAL("Multiple -n options not supported");
@ -656,7 +704,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'N': /* Unicorn mode */ case 'N': /* Unicorn mode */
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); } if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
afl->fsrv.no_unlink = afl->no_unlink = 1; afl->fsrv.no_unlink = (afl->no_unlink = true);
break; break;
@ -906,7 +954,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->power_name = power_names[afl->schedule]; afl->power_name = power_names[afl->schedule];
if (!afl->sync_id) { if (!afl->non_instrumented_mode && !afl->sync_id) {
auto_sync = 1; auto_sync = 1;
afl->sync_id = ck_strdup("default"); afl->sync_id = ck_strdup("default");
@ -1089,6 +1137,23 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (afl->afl_env.afl_crash_exitcode) {
long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
afl->afl_env.afl_crash_exitcode);
}
afl->fsrv.uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
afl->fsrv.crash_exitcode = (u8)exitcode;
}
if (afl->non_instrumented_mode == 2 && afl->no_forkserver) { if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {
FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
@ -1338,7 +1403,11 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (!afl->fsrv.qemu_mode) { check_binary(afl, afl->cmplog_binary); } if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) {
check_binary(afl, afl->cmplog_binary);
}
} }
@ -1380,7 +1449,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
afl->cmplog_fsrv.init_child_func = cmplog_exec_child; afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child_output); afl->afl_env.afl_debug_child);
OKF("Cmplog forkserver successfully started"); OKF("Cmplog forkserver successfully started");
} }
@ -1436,9 +1505,12 @@ int main(int argc, char **argv_orig, char **envp) {
cull_queue(afl); cull_queue(afl);
if (!afl->pending_not_fuzzed) if (!afl->pending_not_fuzzed) {
FATAL("We need at least on valid input seed that does not crash!"); FATAL("We need at least on valid input seed that does not crash!");
}
show_init_stats(afl); show_init_stats(afl);
if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);

View File

@ -182,12 +182,12 @@ static void edit_params(int argc, char **argv) {
instrim = 1; instrim = 1;
if (debug) if (debug)
SAYF(cMGN "[D] " cRST DEBUGF(
"passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s " "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
"inst_present=%s rt_present=%s rt_lto_present=%s\n", "inst_present=%s rt_present=%s rt_lto_present=%s\n",
passthrough ? "true" : "false", instrim, gold_pos, passthrough ? "true" : "false", instrim, gold_pos,
gold_present ? "true" : "false", inst_present ? "true" : "false", gold_present ? "true" : "false", inst_present ? "true" : "false",
rt_present ? "true" : "false", rt_lto_present ? "true" : "false"); rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
@ -280,7 +280,7 @@ int main(int argc, char **argv) {
if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, "."); if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, ".");
SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd); DEBUGF("cd \"%s\";", thecwd);
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
SAYF(" \"%s\"", argv[i]); SAYF(" \"%s\"", argv[i]);
SAYF("\n"); SAYF("\n");
@ -315,7 +315,7 @@ int main(int argc, char **argv) {
if (debug) { if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", thecwd); DEBUGF("cd \"%s\";", thecwd);
for (i = 0; i < ld_param_cnt; i++) for (i = 0; i < ld_param_cnt; i++)
SAYF(" \"%s\"", ld_params[i]); SAYF(" \"%s\"", ld_params[i]);
SAYF("\n"); SAYF("\n");
@ -333,7 +333,7 @@ int main(int argc, char **argv) {
if (pid < 0) PFATAL("fork() failed"); if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status); if (debug) DEBUGF("linker result: %d\n", status);
if (!just_version) { if (!just_version) {

View File

@ -667,6 +667,8 @@ static void usage(u8 *argv0) {
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
"inputs\n" "inputs\n"
"AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n" "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as "
"crash\n"
"AFL_DEBUG: enable extra developer output\n" "AFL_DEBUG: enable extra developer output\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
"size\n" "size\n"
@ -904,7 +906,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (getenv("AFL_DEBUG")) { if (getenv("AFL_DEBUG")) {
SAYF(cMGN "[D]" cRST); DEBUGF("");
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
SAYF(" %s", argv[i]); SAYF(" %s", argv[i]);
SAYF("\n"); SAYF("\n");
@ -1066,7 +1068,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (get_afl_env("AFL_DEBUG")) { if (get_afl_env("AFL_DEBUG")) {
int i = optind; int i = optind;
SAYF(cMGN "[D]" cRST " %s:", fsrv->target_path); DEBUGF("%s:", fsrv->target_path);
while (argv[i] != NULL) { while (argv[i] != NULL) {
SAYF(" \"%s\"", argv[i++]); SAYF(" \"%s\"", argv[i++]);
@ -1090,8 +1092,29 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (getenv("AFL_CRASH_EXITCODE")) {
long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
getenv("AFL_CRASH_EXITCODE"));
}
fsrv->uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
fsrv->crash_exitcode = (u8)exitcode;
}
afl_fsrv_start(fsrv, use_argv, &stop_soon, afl_fsrv_start(fsrv, use_argv, &stop_soon,
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); (get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
? 1
: 0);
map_size = fsrv->map_size; map_size = fsrv->map_size;
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)

View File

@ -51,6 +51,7 @@
#include <signal.h> #include <signal.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/time.h> #include <sys/time.h>
@ -841,17 +842,17 @@ static void usage(u8 *argv0) {
"For additional tips, please consult %s/README.md.\n\n" "For additional tips, please consult %s/README.md.\n\n"
"Environment variables used:\n" "Environment variables used:\n"
"TMPDIR: directory to use for temporary input files\n" "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
"ASAN_OPTIONS: custom settings for ASAN\n" "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n" " the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n" "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" "ASAN_OPTIONS: custom settings for ASAN\n"
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
"TMPDIR: directory to use for temporary input files\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1); exit(1);
@ -1122,6 +1123,23 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (getenv("AFL_CRASH_EXITCODE")) {
long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
getenv("AFL_CRASH_EXITCODE"));
}
fsrv->uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
fsrv->crash_exitcode = (u8)exitcode;
}
shm_fuzz = ck_alloc(sizeof(sharedmem_t)); shm_fuzz = ck_alloc(sizeof(sharedmem_t));
/* initialize cmplog_mode */ /* initialize cmplog_mode */
@ -1141,8 +1159,11 @@ int main(int argc, char **argv_orig, char **envp) {
read_initial_file(); read_initial_file();
afl_fsrv_start(fsrv, use_argv, &stop_soon, afl_fsrv_start(
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
? 1
: 0);
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz); shm_fuzz = deinit_shmem(fsrv, shm_fuzz);

View File

@ -5,7 +5,7 @@
$ECHO "$BLUE[*] Testing: custom mutator" $ECHO "$BLUE[*] Testing: custom mutator"
test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
# normalize path # normalize path
CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../examples/custom_mutators;pwd) CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../utils/custom_mutators;pwd)
test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
unset AFL_CC unset AFL_CC
# Compile the vulnerable program for single mutator # Compile the vulnerable program for single mutator
@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
} }
} }
# Compile the custom mutator # Compile the custom mutator
cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../examples/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../examples/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
test -e test-custom-mutator -a -e ./libexamplemutator.so && { test -e test-custom-mutator -a -e ./libexamplemutator.so && {
# Create input directory # Create input directory
mkdir -p in mkdir -p in
@ -109,7 +109,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
#test "$CODE" = 1 && { $ECHO "$YELLOW[!] custom mutator tests currently will not fail travis" ; CODE=0 ; } #test "$CODE" = 1 && { $ECHO "$YELLOW[!] custom mutator tests currently will not fail travis" ; CODE=0 ; }
make -C ../examples/custom_mutators clean > /dev/null 2>&1 make -C ../utils/custom_mutators clean > /dev/null 2>&1
rm -f test-custom-mutator rm -f test-custom-mutator
rm -f test-custom-mutators rm -f test-custom-mutators
} || { } || {

View File

@ -94,7 +94,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
CODE=1 CODE=1
} }
rm -f test-compcov test.out instrumentlist.txt rm -f test-compcov test.out instrumentlist.txt
../afl-gcc-fast -o test-persistent ../examples/persistent_demo/persistent_demo.c > /dev/null 2>&1 ../afl-gcc-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
test -e test-persistent && { test -e test-persistent && {
echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && { echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
$ECHO "$GREEN[+] gcc_plugin persistent mode feature works correctly" $ECHO "$GREEN[+] gcc_plugin persistent mode feature works correctly"

View File

@ -57,7 +57,7 @@ test -e ../afl-clang-lto -a -e ../afl-llvm-lto-instrumentation.so && {
CODE=1 CODE=1
} }
rm -f test-compcov test.out instrumentlist.txt rm -f test-compcov test.out instrumentlist.txt
../afl-clang-lto -o test-persistent ../examples/persistent_demo/persistent_demo.c > /dev/null 2>&1 ../afl-clang-lto -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
test -e test-persistent && { test -e test-persistent && {
echo foo | ../afl-showmap -m none -o /dev/null -q -r ./test-persistent && { echo foo | ../afl-showmap -m none -o /dev/null -q -r ./test-persistent && {
$ECHO "$GREEN[+] llvm_mode LTO persistent mode feature works correctly" $ECHO "$GREEN[+] llvm_mode LTO persistent mode feature works correctly"

View File

@ -209,7 +209,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
INCOMPLETE=1 INCOMPLETE=1
} }
rm -rf errors test-cmplog in core.* rm -rf errors test-cmplog in core.*
../afl-clang-fast -o test-persistent ../examples/persistent_demo/persistent_demo.c > /dev/null 2>&1 ../afl-clang-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
test -e test-persistent && { test -e test-persistent && {
echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && { echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
$ECHO "$GREEN[+] llvm_mode persistent mode feature works correctly" $ECHO "$GREEN[+] llvm_mode persistent mode feature works correctly"

View File

@ -135,4 +135,4 @@ test -z "$SYS" && $ECHO "$YELLOW[-] uname -m did not succeed"
CODE=0 CODE=0
INCOMPLETE=0 INCOMPLETE=0
fi fi

View File

@ -7,7 +7,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
test -e ../unicorn_mode/samples/simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && { test -e ../unicorn_mode/samples/simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && {
{ {
# We want to see python errors etc. in logs, in case something doesn't work # We want to see python errors etc. in logs, in case something doesn't work
export AFL_DEBUG_CHILD_OUTPUT=1 export AFL_DEBUG_CHILD=1
# some python version should be available now # some python version should be available now
PYTHONS="`command -v python3` `command -v python` `command -v python2`" PYTHONS="`command -v python3` `command -v python` `command -v python2`"
@ -34,7 +34,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
cd ../unicorn_mode/samples/persistent cd ../unicorn_mode/samples/persistent
make >>errors 2>&1 make >>errors 2>&1
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds" $ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds"
AFL_DEBUG_CHILD_OUTPUT=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1 AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)" $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)"
} || { } || {
@ -96,7 +96,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
} }
fi fi
unset AFL_DEBUG_CHILD_OUTPUT unset AFL_DEBUG_CHILD
} }
} || { } || {

View File

@ -1 +1 @@
f44ec48f 8cca4801

View File

@ -149,7 +149,7 @@ git status 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "[*] initializing unicornafl submodule" echo "[*] initializing unicornafl submodule"
git submodule init || exit 1 git submodule init || exit 1
git submodule update 2>/dev/null # ignore errors git submodule update ./unicornafl 2>/dev/null # ignore errors
else else
echo "[*] cloning unicornafl" echo "[*] cloning unicornafl"
test -d unicornafl || { test -d unicornafl || {

View File

@ -1,13 +1,13 @@
""" """
unicorn_dumper_gdb.py unicorn_dumper_gdb.py
When run with GDB sitting at a debug breakpoint, this When run with GDB sitting at a debug breakpoint, this
dumps the current state (registers/memory/etc) of dumps the current state (registers/memory/etc) of
the process to a directory consisting of an index the process to a directory consisting of an index
file with register and segment information and file with register and segment information and
sub-files containing all actual process memory. sub-files containing all actual process memory.
The output of this script is expected to be used The output of this script is expected to be used
to initialize context for Unicorn emulation. to initialize context for Unicorn emulation.
----------- -----------
@ -44,6 +44,7 @@ MAX_SEG_SIZE = 128 * 1024 * 1024
# Name of the index file # Name of the index file
INDEX_FILE_NAME = "_index.json" INDEX_FILE_NAME = "_index.json"
#---------------------- #----------------------
#---- Helper Functions #---- Helper Functions
@ -59,14 +60,14 @@ def map_arch():
return "arm64be" return "arm64be"
elif 'armeb' in arch: elif 'armeb' in arch:
# check for THUMB mode # check for THUMB mode
cpsr = get_register('cpsr') cpsr = get_register('$cpsr')
if (cpsr & (1 << 5)): if (cpsr & (1 << 5)):
return "armbethumb" return "armbethumb"
else: else:
return "armbe" return "armbe"
elif 'arm' in arch: elif 'arm' in arch:
# check for THUMB mode # check for THUMB mode
cpsr = get_register('cpsr') cpsr = get_register('$cpsr')
if (cpsr & (1 << 5)): if (cpsr & (1 << 5)):
return "armlethumb" return "armlethumb"
else: else:
@ -88,19 +89,15 @@ def dump_regs():
reg_state = {} reg_state = {}
for reg in current_arch.all_registers: for reg in current_arch.all_registers:
reg_val = get_register(reg) reg_val = get_register(reg)
# current dumper script looks for register values to be hex strings
# reg_str = "0x{:08x}".format(reg_val)
# if "64" in get_arch():
# reg_str = "0x{:016x}".format(reg_val)
# reg_state[reg.strip().strip('$')] = reg_str
reg_state[reg.strip().strip('$')] = reg_val reg_state[reg.strip().strip('$')] = reg_val
return reg_state return reg_state
def dump_process_memory(output_dir): def dump_process_memory(output_dir):
# Segment information dictionary # Segment information dictionary
final_segment_list = [] final_segment_list = []
# GEF: # GEF:
vmmap = get_process_maps() vmmap = get_process_maps()
if not vmmap: if not vmmap:
@ -110,7 +107,7 @@ def dump_process_memory(output_dir):
for entry in vmmap: for entry in vmmap:
if entry.page_start == entry.page_end: if entry.page_start == entry.page_end:
continue continue
seg_info = {'start': entry.page_start, 'end': entry.page_end, 'name': entry.path, 'permissions': { seg_info = {'start': entry.page_start, 'end': entry.page_end, 'name': entry.path, 'permissions': {
"r": entry.is_readable() > 0, "r": entry.is_readable() > 0,
"w": entry.is_writable() > 0, "w": entry.is_writable() > 0,
@ -129,7 +126,7 @@ def dump_process_memory(output_dir):
compressed_seg_content = zlib.compress(seg_content) compressed_seg_content = zlib.compress(seg_content)
md5_sum = hashlib.md5(compressed_seg_content).hexdigest() + ".bin" md5_sum = hashlib.md5(compressed_seg_content).hexdigest() + ".bin"
seg_info["content_file"] = md5_sum seg_info["content_file"] = md5_sum
# Write the compressed contents to disk # Write the compressed contents to disk
out_file = open(os.path.join(output_dir, md5_sum), 'wb') out_file = open(os.path.join(output_dir, md5_sum), 'wb')
out_file.write(compressed_seg_content) out_file.write(compressed_seg_content)
@ -143,12 +140,27 @@ def dump_process_memory(output_dir):
# Add the segment to the list # Add the segment to the list
final_segment_list.append(seg_info) final_segment_list.append(seg_info)
return final_segment_list return final_segment_list
#---------------------------------------------
#---- ARM Extention (dump floating point regs)
def dump_float(rge=32):
reg_convert = ""
if map_arch() == "armbe" or map_arch() == "armle" or map_arch() == "armbethumb" or map_arch() == "armbethumb":
reg_state = {}
for reg_num in range(32):
value = gdb.selected_frame().read_register("d" + str(reg_num))
reg_state["d" + str(reg_num)] = int(str(value["u64"]), 16)
value = gdb.selected_frame().read_register("fpscr")
reg_state["fpscr"] = int(str(value), 16)
return reg_state
#---------- #----------
#---- Main #---- Main
def main(): def main():
print("----- Unicorn Context Dumper -----") print("----- Unicorn Context Dumper -----")
print("You must be actively debugging before running this!") print("You must be actively debugging before running this!")
@ -159,32 +171,32 @@ def main():
print("!!! GEF not running in GDB. Please run gef.py by executing:") print("!!! GEF not running in GDB. Please run gef.py by executing:")
print('\tpython execfile ("<path_to_gef>/gef.py")') print('\tpython execfile ("<path_to_gef>/gef.py")')
return return
try: try:
# Create the output directory # Create the output directory
timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d_%H%M%S') timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d_%H%M%S')
output_path = "UnicornContext_" + timestamp output_path = "UnicornContext_" + timestamp
if not os.path.exists(output_path): if not os.path.exists(output_path):
os.makedirs(output_path) os.makedirs(output_path)
print("Process context will be output to {}".format(output_path)) print("Process context will be output to {}".format(output_path))
# Get the context # Get the context
context = { context = {
"arch": dump_arch_info(), "arch": dump_arch_info(),
"regs": dump_regs(), "regs": dump_regs(),
"regs_extended": dump_float(),
"segments": dump_process_memory(output_path), "segments": dump_process_memory(output_path),
} }
# Write the index file # Write the index file
index_file = open(os.path.join(output_path, INDEX_FILE_NAME), 'w') index_file = open(os.path.join(output_path, INDEX_FILE_NAME), 'w')
index_file.write(json.dumps(context, indent=4)) index_file.write(json.dumps(context, indent=4))
index_file.close() index_file.close()
print("Done.") print("Done.")
except Exception as e: except Exception as e:
print("!!! ERROR:\n\t{}".format(repr(e))) print("!!! ERROR:\n\t{}".format(repr(e)))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -206,4 +206,4 @@ def main():
print("!!! ERROR:\n\t{}".format(str(e))) print("!!! ERROR:\n\t{}".format(str(e)))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,8 +1,8 @@
""" """
unicorn_loader.py unicorn_loader.py
Loads a process context dumped created using a Loads a process context dumped created using a
Unicorn Context Dumper script into a Unicorn Engine Unicorn Context Dumper script into a Unicorn Engine
instance. Once this is performed emulation can be instance. Once this is performed emulation can be
started. started.
""" """
@ -26,6 +26,13 @@ from unicorn.arm64_const import *
from unicorn.x86_const import * from unicorn.x86_const import *
from unicorn.mips_const import * from unicorn.mips_const import *
# If Capstone libraries are availible (only check once)
try:
from capstone import *
CAPSTONE_EXISTS = 1
except:
CAPSTONE_EXISTS = 0
# Name of the index file # Name of the index file
INDEX_FILE_NAME = "_index.json" INDEX_FILE_NAME = "_index.json"
@ -86,7 +93,7 @@ class UnicornSimpleHeap(object):
total_chunk_size = UNICORN_PAGE_SIZE + ALIGN_PAGE_UP(size) + UNICORN_PAGE_SIZE total_chunk_size = UNICORN_PAGE_SIZE + ALIGN_PAGE_UP(size) + UNICORN_PAGE_SIZE
# Gross but efficient way to find space for the chunk: # Gross but efficient way to find space for the chunk:
chunk = None chunk = None
for addr in xrange(self.HEAP_MIN_ADDR, self.HEAP_MAX_ADDR, UNICORN_PAGE_SIZE): for addr in range(self.HEAP_MIN_ADDR, self.HEAP_MAX_ADDR, UNICORN_PAGE_SIZE):
try: try:
self._uc.mem_map(addr, total_chunk_size, UC_PROT_READ | UC_PROT_WRITE) self._uc.mem_map(addr, total_chunk_size, UC_PROT_READ | UC_PROT_WRITE)
chunk = self.HeapChunk(addr, total_chunk_size, size) chunk = self.HeapChunk(addr, total_chunk_size, size)
@ -97,7 +104,7 @@ class UnicornSimpleHeap(object):
continue continue
# Something went very wrong # Something went very wrong
if chunk == None: if chunk == None:
return 0 return 0
self._chunks.append(chunk) self._chunks.append(chunk)
return chunk.data_addr return chunk.data_addr
@ -112,8 +119,8 @@ class UnicornSimpleHeap(object):
old_chunk = None old_chunk = None
for chunk in self._chunks: for chunk in self._chunks:
if chunk.data_addr == ptr: if chunk.data_addr == ptr:
old_chunk = chunk old_chunk = chunk
new_chunk_addr = self.malloc(new_size) new_chunk_addr = self.malloc(new_size)
if old_chunk != None: if old_chunk != None:
self._uc.mem_write(new_chunk_addr, str(self._uc.mem_read(old_chunk.data_addr, old_chunk.data_size))) self._uc.mem_write(new_chunk_addr, str(self._uc.mem_read(old_chunk.data_addr, old_chunk.data_size)))
self.free(old_chunk.data_addr) self.free(old_chunk.data_addr)
@ -184,39 +191,27 @@ class AflUnicornEngine(Uc):
# Load the registers # Load the registers
regs = context['regs'] regs = context['regs']
reg_map = self.__get_register_map(self._arch_str) reg_map = self.__get_register_map(self._arch_str)
for register, value in regs.iteritems(): self.__load_registers(regs, reg_map, debug_print)
if debug_print: # If we have extra FLOATING POINT regs, load them in!
print("Reg {0} = {1}".format(register, value)) if 'regs_extended' in context:
if not reg_map.has_key(register.lower()): if context['regs_extended']:
if debug_print: regs_extended = context['regs_extended']
print("Skipping Reg: {}".format(register)) reg_map = self.__get_registers_extended(self._arch_str)
else: self.__load_registers(regs_extended, reg_map, debug_print)
reg_write_retry = True
try: # For ARM, sometimes the stack pointer is erased ??? (I think I fixed this (issue with ordering of dumper.py, I'll keep the write anyways)
self.reg_write(reg_map[register.lower()], value) if self.__get_arch_and_mode(self.get_arch_str())[0] == UC_ARCH_ARM:
reg_write_retry = False self.reg_write(UC_ARM_REG_SP, regs['sp'])
except Exception as e:
if debug_print:
print("ERROR writing register: {}, value: {} -- {}".format(register, value, repr(e)))
if reg_write_retry:
if debug_print:
print("Trying to parse value ({}) as hex string".format(value))
try:
self.reg_write(reg_map[register.lower()], int(value, 16))
except Exception as e:
if debug_print:
print("ERROR writing hex string register: {}, value: {} -- {}".format(register, value, repr(e)))
# Setup the memory map and load memory content # Setup the memory map and load memory content
self.__map_segments(context['segments'], context_directory, debug_print) self.__map_segments(context['segments'], context_directory, debug_print)
if enable_trace: if enable_trace:
self.hook_add(UC_HOOK_BLOCK, self.__trace_block) self.hook_add(UC_HOOK_BLOCK, self.__trace_block)
self.hook_add(UC_HOOK_CODE, self.__trace_instruction) self.hook_add(UC_HOOK_CODE, self.__trace_instruction)
self.hook_add(UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, self.__trace_mem_access) self.hook_add(UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, self.__trace_mem_access)
self.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_READ_INVALID, self.__trace_mem_invalid_access) self.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_READ_INVALID, self.__trace_mem_invalid_access)
if debug_print: if debug_print:
print("Done loading context.") print("Done loading context.")
@ -228,7 +223,7 @@ class AflUnicornEngine(Uc):
def get_arch_str(self): def get_arch_str(self):
return self._arch_str return self._arch_str
def force_crash(self, uc_error): def force_crash(self, uc_error):
""" This function should be called to indicate to AFL that a crash occurred during emulation. """ This function should be called to indicate to AFL that a crash occurred during emulation.
You can pass the exception received from Uc.emu_start You can pass the exception received from Uc.emu_start
@ -253,21 +248,76 @@ class AflUnicornEngine(Uc):
for reg in sorted(self.__get_register_map(self._arch_str).items(), key=lambda reg: reg[0]): for reg in sorted(self.__get_register_map(self._arch_str).items(), key=lambda reg: reg[0]):
print(">>> {0:>4}: 0x{1:016x}".format(reg[0], self.reg_read(reg[1]))) print(">>> {0:>4}: 0x{1:016x}".format(reg[0], self.reg_read(reg[1])))
def dump_regs_extended(self):
""" Dumps the contents of all the registers to STDOUT """
try:
for reg in sorted(self.__get_registers_extended(self._arch_str).items(), key=lambda reg: reg[0]):
print(">>> {0:>4}: 0x{1:016x}".format(reg[0], self.reg_read(reg[1])))
except Exception as e:
print("ERROR: Are extended registers loaded?")
# TODO: Make this dynamically get the stack pointer register and pointer width for the current architecture # TODO: Make this dynamically get the stack pointer register and pointer width for the current architecture
""" """
def dump_stack(self, window=10): def dump_stack(self, window=10):
arch = self.get_arch()
mode = self.get_mode()
# Get stack pointers and bit sizes for given architecture
if arch == UC_ARCH_X86 and mode == UC_MODE_64:
stack_ptr_addr = self.reg_read(UC_X86_REG_RSP)
bit_size = 8
elif arch == UC_ARCH_X86 and mode == UC_MODE_32:
stack_ptr_addr = self.reg_read(UC_X86_REG_ESP)
bit_size = 4
elif arch == UC_ARCH_ARM64:
stack_ptr_addr = self.reg_read(UC_ARM64_REG_SP)
bit_size = 8
elif arch == UC_ARCH_ARM:
stack_ptr_addr = self.reg_read(UC_ARM_REG_SP)
bit_size = 4
elif arch == UC_ARCH_ARM and mode == UC_MODE_THUMB:
stack_ptr_addr = self.reg_read(UC_ARM_REG_SP)
bit_size = 4
elif arch == UC_ARCH_MIPS:
stack_ptr_addr = self.reg_read(UC_MIPS_REG_SP)
bit_size = 4
print("")
print(">>> Stack:") print(">>> Stack:")
stack_ptr_addr = self.reg_read(UC_X86_REG_RSP) stack_ptr_addr = self.reg_read(UC_X86_REG_RSP)
for i in xrange(-window, window + 1): for i in xrange(-window, window + 1):
addr = stack_ptr_addr + (i*8) addr = stack_ptr_addr + (i*8)
print("{0}0x{1:016x}: 0x{2:016x}".format( \ print("{0}0x{1:016x}: 0x{2:016x}".format( \
'SP->' if i == 0 else ' ', addr, \ 'SP->' if i == 0 else ' ', addr, \
struct.unpack('<Q', self.mem_read(addr, 8))[0])) struct.unpack('<Q', self.mem_read(addr, 8))[0]))
""" """
#----------------------------- #-----------------------------
#---- Loader Helper Functions #---- Loader Helper Functions
def __load_registers(self, regs, reg_map, debug_print):
for register, value in regs.items():
if debug_print:
print("Reg {0} = {1}".format(register, value))
if register.lower() not in reg_map:
if debug_print:
print("Skipping Reg: {}".format(register))
else:
reg_write_retry = True
try:
self.reg_write(reg_map[register.lower()], value)
reg_write_retry = False
except Exception as e:
if debug_print:
print("ERROR writing register: {}, value: {} -- {}".format(register, value, repr(e)))
if reg_write_retry:
if debug_print:
print("Trying to parse value ({}) as hex string".format(value))
try:
self.reg_write(reg_map[register.lower()], int(value, 16))
except Exception as e:
if debug_print:
print("ERROR writing hex string register: {}, value: {} -- {}".format(register, value, repr(e)))
def __map_segment(self, name, address, size, perms, debug_print=False): def __map_segment(self, name, address, size, perms, debug_print=False):
# - size is unsigned and must be != 0 # - size is unsigned and must be != 0
# - starting address must be aligned to 4KB # - starting address must be aligned to 4KB
@ -289,7 +339,7 @@ class AflUnicornEngine(Uc):
def __map_segments(self, segment_list, context_directory, debug_print=False): def __map_segments(self, segment_list, context_directory, debug_print=False):
for segment in segment_list: for segment in segment_list:
# Get the segment information from the index # Get the segment information from the index
name = segment['name'] name = segment['name']
seg_start = segment['start'] seg_start = segment['start']
@ -297,7 +347,7 @@ class AflUnicornEngine(Uc):
perms = \ perms = \
(UC_PROT_READ if segment['permissions']['r'] == True else 0) | \ (UC_PROT_READ if segment['permissions']['r'] == True else 0) | \
(UC_PROT_WRITE if segment['permissions']['w'] == True else 0) | \ (UC_PROT_WRITE if segment['permissions']['w'] == True else 0) | \
(UC_PROT_EXEC if segment['permissions']['x'] == True else 0) (UC_PROT_EXEC if segment['permissions']['x'] == True else 0)
if debug_print: if debug_print:
print("Handling segment {}".format(name)) print("Handling segment {}".format(name))
@ -349,12 +399,12 @@ class AflUnicornEngine(Uc):
content_file = open(content_file_path, 'rb') content_file = open(content_file_path, 'rb')
compressed_content = content_file.read() compressed_content = content_file.read()
content_file.close() content_file.close()
self.mem_write(seg_start, zlib.decompress(compressed_content)) self.mem_write(seg_start, zlib.decompress(compressed_content))
else: else:
if debug_print: if debug_print:
print("No content found for segment {0} @ {1:016x}".format(name, seg_start)) print("No content found for segment {0} @ {1:016x}".format(name, seg_start))
self.mem_write(seg_start, '\x00' * (seg_end - seg_start)) self.mem_write(seg_start, b'\x00' * (seg_end - seg_start))
def __get_arch_and_mode(self, arch_str): def __get_arch_and_mode(self, arch_str):
arch_map = { arch_map = {
@ -398,7 +448,6 @@ class AflUnicornEngine(Uc):
"r14": UC_X86_REG_R14, "r14": UC_X86_REG_R14,
"r15": UC_X86_REG_R15, "r15": UC_X86_REG_R15,
"rip": UC_X86_REG_RIP, "rip": UC_X86_REG_RIP,
"rsp": UC_X86_REG_RSP,
"efl": UC_X86_REG_EFLAGS, "efl": UC_X86_REG_EFLAGS,
"cs": UC_X86_REG_CS, "cs": UC_X86_REG_CS,
"ds": UC_X86_REG_DS, "ds": UC_X86_REG_DS,
@ -415,13 +464,12 @@ class AflUnicornEngine(Uc):
"esi": UC_X86_REG_ESI, "esi": UC_X86_REG_ESI,
"edi": UC_X86_REG_EDI, "edi": UC_X86_REG_EDI,
"ebp": UC_X86_REG_EBP, "ebp": UC_X86_REG_EBP,
"esp": UC_X86_REG_ESP,
"eip": UC_X86_REG_EIP, "eip": UC_X86_REG_EIP,
"esp": UC_X86_REG_ESP, "esp": UC_X86_REG_ESP,
"efl": UC_X86_REG_EFLAGS, "efl": UC_X86_REG_EFLAGS,
# Segment registers removed... # Segment registers removed...
# They caused segfaults (from unicorn?) when they were here # They caused segfaults (from unicorn?) when they were here
}, },
"arm" : { "arm" : {
"r0": UC_ARM_REG_R0, "r0": UC_ARM_REG_R0,
"r1": UC_ARM_REG_R1, "r1": UC_ARM_REG_R1,
@ -476,7 +524,7 @@ class AflUnicornEngine(Uc):
"fp": UC_ARM64_REG_FP, "fp": UC_ARM64_REG_FP,
"lr": UC_ARM64_REG_LR, "lr": UC_ARM64_REG_LR,
"nzcv": UC_ARM64_REG_NZCV, "nzcv": UC_ARM64_REG_NZCV,
"cpsr": UC_ARM_REG_CPSR, "cpsr": UC_ARM_REG_CPSR,
}, },
"mips" : { "mips" : {
"0" : UC_MIPS_REG_ZERO, "0" : UC_MIPS_REG_ZERO,
@ -499,13 +547,13 @@ class AflUnicornEngine(Uc):
"t9": UC_MIPS_REG_T9, "t9": UC_MIPS_REG_T9,
"s0": UC_MIPS_REG_S0, "s0": UC_MIPS_REG_S0,
"s1": UC_MIPS_REG_S1, "s1": UC_MIPS_REG_S1,
"s2": UC_MIPS_REG_S2, "s2": UC_MIPS_REG_S2,
"s3": UC_MIPS_REG_S3, "s3": UC_MIPS_REG_S3,
"s4": UC_MIPS_REG_S4, "s4": UC_MIPS_REG_S4,
"s5": UC_MIPS_REG_S5, "s5": UC_MIPS_REG_S5,
"s6": UC_MIPS_REG_S6, "s6": UC_MIPS_REG_S6,
"s7": UC_MIPS_REG_S7, "s7": UC_MIPS_REG_S7,
"s8": UC_MIPS_REG_S8, "s8": UC_MIPS_REG_S8,
"k0": UC_MIPS_REG_K0, "k0": UC_MIPS_REG_K0,
"k1": UC_MIPS_REG_K1, "k1": UC_MIPS_REG_K1,
"gp": UC_MIPS_REG_GP, "gp": UC_MIPS_REG_GP,
@ -517,44 +565,127 @@ class AflUnicornEngine(Uc):
"lo": UC_MIPS_REG_LO "lo": UC_MIPS_REG_LO
} }
} }
return registers[arch] return registers[arch]
def __get_registers_extended(self, arch):
# Similar to __get_register_map, but for ARM floating point registers
if arch == "arm64le" or arch == "arm64be":
arch = "arm64"
elif arch == "armle" or arch == "armbe" or "thumb" in arch:
arch = "arm"
elif arch == "mipsel":
arch = "mips"
registers = {
"arm": {
"d0": UC_ARM_REG_D0,
"d1": UC_ARM_REG_D1,
"d2": UC_ARM_REG_D2,
"d3": UC_ARM_REG_D3,
"d4": UC_ARM_REG_D4,
"d5": UC_ARM_REG_D5,
"d6": UC_ARM_REG_D6,
"d7": UC_ARM_REG_D7,
"d8": UC_ARM_REG_D8,
"d9": UC_ARM_REG_D9,
"d10": UC_ARM_REG_D10,
"d11": UC_ARM_REG_D11,
"d12": UC_ARM_REG_D12,
"d13": UC_ARM_REG_D13,
"d14": UC_ARM_REG_D14,
"d15": UC_ARM_REG_D15,
"d16": UC_ARM_REG_D16,
"d17": UC_ARM_REG_D17,
"d18": UC_ARM_REG_D18,
"d19": UC_ARM_REG_D19,
"d20": UC_ARM_REG_D20,
"d21": UC_ARM_REG_D21,
"d22": UC_ARM_REG_D22,
"d23": UC_ARM_REG_D23,
"d24": UC_ARM_REG_D24,
"d25": UC_ARM_REG_D25,
"d26": UC_ARM_REG_D26,
"d27": UC_ARM_REG_D27,
"d28": UC_ARM_REG_D28,
"d29": UC_ARM_REG_D29,
"d30": UC_ARM_REG_D30,
"d31": UC_ARM_REG_D31,
"fpscr": UC_ARM_REG_FPSCR
}
}
return registers[arch];
#--------------------------- #---------------------------
# Callbacks for tracing # Callbacks for tracing
# TODO: Make integer-printing fixed widths dependent on bitness of architecture
# (i.e. only show 4 bytes for 32-bit, 8 bytes for 64-bit)
# TODO: Figure out how best to determine the capstone mode and architecture here # TODO: Extra mode for Capstone (i.e. Cs(cs_arch, cs_mode + cs_extra) not implemented
"""
try:
# If Capstone is installed then we'll dump disassembly, otherwise just dump the binary.
from capstone import *
cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
def __trace_instruction(self, uc, address, size, user_data):
mem = uc.mem_read(address, size)
for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(bytes(mem), size):
print(" Instr: {:#016x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr))
except ImportError:
def __trace_instruction(self, uc, address, size, user_data):
print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
"""
def __trace_instruction(self, uc, address, size, user_data): def __trace_instruction(self, uc, address, size, user_data):
print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size)) if CAPSTONE_EXISTS == 1:
# If Capstone is installed then we'll dump disassembly, otherwise just dump the binary.
arch = self.get_arch()
mode = self.get_mode()
bit_size = self.bit_size_arch()
# Map current arch to capstone labeling
if arch == UC_ARCH_X86 and mode == UC_MODE_64:
cs_arch = CS_ARCH_X86
cs_mode = CS_MODE_64
elif arch == UC_ARCH_X86 and mode == UC_MODE_32:
cs_arch = CS_ARCH_X86
cs_mode = CS_MODE_32
elif arch == UC_ARCH_ARM64:
cs_arch = CS_ARCH_ARM64
cs_mode = CS_MODE_ARM
elif arch == UC_ARCH_ARM and mode == UC_MODE_THUMB:
cs_arch = CS_ARCH_ARM
cs_mode = CS_MODE_THUMB
elif arch == UC_ARCH_ARM:
cs_arch = CS_ARCH_ARM
cs_mode = CS_MODE_ARM
elif arch == UC_ARCH_MIPS:
cs_arch = CS_ARCH_MIPS
cs_mode = CS_MODE_MIPS32 # No other MIPS supported in program
cs = Cs(cs_arch, cs_mode)
mem = uc.mem_read(address, size)
if bit_size == 4:
for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(bytes(mem), size):
print(" Instr: {:#08x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr))
else:
for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(bytes(mem), size):
print(" Instr: {:#16x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr))
else:
print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
def __trace_block(self, uc, address, size, user_data): def __trace_block(self, uc, address, size, user_data):
print("Basic Block: addr=0x{0:016x}, size=0x{1:016x}".format(address, size)) print("Basic Block: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
def __trace_mem_access(self, uc, access, address, size, value, user_data): def __trace_mem_access(self, uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE: if access == UC_MEM_WRITE:
print(" >>> Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value)) print(" >>> Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value))
else: else:
print(" >>> Read: addr=0x{0:016x} size={1}".format(address, size)) print(" >>> Read: addr=0x{0:016x} size={1}".format(address, size))
def __trace_mem_invalid_access(self, uc, access, address, size, value, user_data): def __trace_mem_invalid_access(self, uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE_UNMAPPED: if access == UC_MEM_WRITE_UNMAPPED:
print(" >>> INVALID Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value)) print(" >>> INVALID Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value))
else: else:
print(" >>> INVALID Read: addr=0x{0:016x} size={1}".format(address, size)) print(" >>> INVALID Read: addr=0x{0:016x} size={1}".format(address, size))
def bit_size_arch(self):
arch = self.get_arch()
mode = self.get_mode()
# Get bit sizes for given architecture
if arch == UC_ARCH_X86 and mode == UC_MODE_64:
bit_size = 8
elif arch == UC_ARCH_X86 and mode == UC_MODE_32:
bit_size = 4
elif arch == UC_ARCH_ARM64:
bit_size = 8
elif arch == UC_ARCH_ARM:
bit_size = 4
elif arch == UC_ARCH_MIPS:
bit_size = 4
return bit_size

@ -1 +1 @@
Subproject commit c6d6647161a32bae88785a618fcd828d1711d9e6 Subproject commit 8cca4801adb767dce7cf72202d7d25bdb420cf7d

View File

@ -39,13 +39,13 @@ Here's a quick overview of the stuff you can find in this directory:
- libpng_no_checksum - a sample patch for removing CRC checks in libpng. - libpng_no_checksum - a sample patch for removing CRC checks in libpng.
- persistent_demo - an example of how to use the LLVM persistent process - persistent_mode - an example of how to use the LLVM persistent process
mode to speed up certain fuzzing jobs. mode to speed up certain fuzzing jobs.
- socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
for fuzzing access with afl++ for fuzzing access with afl++
Note that the minimize_corpus.sh tool has graduated from the examples/ Note that the minimize_corpus.sh tool has graduated from the utils/
directory and is now available as ../afl-cmin. The LLVM mode has likewise directory and is now available as ../afl-cmin. The LLVM mode has likewise
graduated to ../instrumentation/*. graduated to ../instrumentation/*.

View File

@ -358,8 +358,8 @@ int recv_testcase(int s, void **buf) {
if ((size & 0xff000000) != 0xff000000) { if ((size & 0xff000000) != 0xff000000) {
*buf = afl_realloc((void **)&buf, size); *buf = afl_realloc(buf, size);
if (unlikely(!buf)) { PFATAL("Alloc"); } if (unlikely(!*buf)) { PFATAL("Alloc"); }
received = 0; received = 0;
// fprintf(stderr, "unCOMPRESS (%u)\n", size); // fprintf(stderr, "unCOMPRESS (%u)\n", size);
while (received < size && while (received < size &&
@ -371,8 +371,8 @@ int recv_testcase(int s, void **buf) {
#ifdef USE_DEFLATE #ifdef USE_DEFLATE
u32 clen; u32 clen;
size -= 0xff000000; size -= 0xff000000;
*buf = afl_realloc((void **)&buf, size); *buf = afl_realloc(buf, size);
if (unlikely(!buf)) { PFATAL("Alloc"); } if (unlikely(!*buf)) { PFATAL("Alloc"); }
received = 0; received = 0;
while (received < 4 && while (received < 4 &&
(ret = recv(s, &clen + received, 4 - received, 0)) > 0) (ret = recv(s, &clen + received, 4 - received, 0)) > 0)
@ -636,8 +636,11 @@ int main(int argc, char **argv_orig, char **envp) {
if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
afl_fsrv_start(fsrv, use_argv, &stop_soon, afl_fsrv_start(
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
? 1
: 0);
#ifdef USE_DEFLATE #ifdef USE_DEFLATE
compressor = libdeflate_alloc_compressor(1); compressor = libdeflate_alloc_compressor(1);

Some files were not shown because too many files have changed in this diff Show More