mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-09 00:31:33 +00:00
Merge branch 'dev' of github.com:AFLplusplus/AFLplusplus into dev
This commit is contained in:
commit
ad29eef271
@ -29,7 +29,7 @@ CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
|
||||
if CLANG_FORMAT_BIN is None:
|
||||
o = 0
|
||||
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 = str(o, "utf-8")
|
||||
o = re.sub(r".*ersion ", "", o)
|
||||
@ -37,7 +37,7 @@ if CLANG_FORMAT_BIN is None:
|
||||
o = o[:o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
print ("clang-format-10 is needed. Aborted.")
|
||||
print ("clang-format-11 is needed. Aborted.")
|
||||
exit(1)
|
||||
#if o < 7:
|
||||
# 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'
|
||||
# elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-9'
|
||||
# elif subprocess.call(['which', 'clang-format-10'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-10'
|
||||
# elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
# else:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = 'clang-format-10'
|
||||
CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
a.out
|
||||
ld
|
||||
in
|
||||
out
|
||||
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -1,9 +1,8 @@
|
||||
[submodule "unicorn_mode/unicornafl"]
|
||||
path = unicorn_mode/unicornafl
|
||||
url = https://github.com/AFLplusplus/unicornafl
|
||||
|
||||
[submodule "custom_mutators/Grammar-Mutator"]
|
||||
path = custom_mutators/Grammar-Mutator
|
||||
[submodule "custom_mutators/grammar_mutator"]
|
||||
path = custom_mutators/grammar_mutator/grammar_mutator
|
||||
url = https://github.com/AFLplusplus/Grammar-Mutator
|
||||
[submodule "qemu_mode/qemuafl"]
|
||||
path = qemu_mode/qemuafl
|
||||
|
@ -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.
|
||||
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, ...).
|
||||
|
||||
Remember that AFLplusplus has to build and run on many platforms, so
|
||||
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.
|
||||
|
48
GNUmakefile
48
GNUmakefile
@ -85,8 +85,10 @@ ifneq "$(shell uname)" "Darwin"
|
||||
endif
|
||||
endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
@ -232,7 +234,9 @@ else
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
ifndef DEBUG
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
LDFLAGS += -ldl -lrt -lm
|
||||
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
|
||||
|
||||
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
|
||||
$(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 custom_mutators/*/*.c* # destroys libfuzzer :-(
|
||||
@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
|
||||
./.custom-format.py -i examples/*/*.c*
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i utils/*/*.c*
|
||||
./.custom-format.py -i utils/*/*.h
|
||||
./.custom-format.py -i test/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
@ -512,7 +516,7 @@ code-format:
|
||||
ifndef AFL_NO_X86
|
||||
test_build: afl-cc afl-as afl-showmap
|
||||
@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
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@ -538,14 +542,14 @@ all_done: test_build
|
||||
|
||||
.PHONY: 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.gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/afl_network_proxy clean
|
||||
$(MAKE) -C examples/socket_fuzzing clean
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C utils/afl_network_proxy clean
|
||||
$(MAKE) -C utils/socket_fuzzing clean
|
||||
$(MAKE) -C utils/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
@ -568,10 +572,10 @@ distrib: all
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/aflpp_driver
|
||||
$(MAKE) -C examples/afl_network_proxy
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
$(MAKE) -C utils/aflpp_driver
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
@ -579,9 +583,9 @@ distrib: all
|
||||
binary-only: all
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/afl_network_proxy
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-cd qemu_mode && sh ./build_qemu_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) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/aflpp_driver
|
||||
$(MAKE) -C utils/aflpp_driver
|
||||
|
||||
%.8: %
|
||||
@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 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 socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
@if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/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 examples/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 examples/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); 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 utils/argv_fuzzing install; fi
|
||||
@if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; 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 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.gcc_plugin install
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
|
||||
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
#TEST_MMAP=1
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
|
@ -34,7 +34,7 @@ ifeq "$(shell uname)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 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
|
||||
else
|
||||
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-gcc
|
||||
@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++
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
|
22
README.md
22
README.md
@ -22,8 +22,8 @@
|
||||
afl++ is a superior fork to Google's afl - more speed, more and better
|
||||
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/)
|
||||
in the website.
|
||||
If you want to use afl++ for your academic work, check the [papers page](https://aflplus.plus/papers/)
|
||||
on the website.
|
||||
|
||||
## 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
|
||||
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).
|
||||
* examples/ got renamed to utils/
|
||||
|
||||
## Contents
|
||||
|
||||
@ -273,7 +274,7 @@ anything below 9 is not recommended.
|
||||
v
|
||||
+---------------------------------+
|
||||
| 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/++
|
||||
|
|
||||
@ -292,7 +293,7 @@ anything below 9 is not recommended.
|
||||
Clickable README links for the chosen compiler:
|
||||
|
||||
* [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 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,
|
||||
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 @@`
|
||||
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
|
||||
(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
|
||||
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
|
||||
@ -760,10 +761,10 @@ cd unicorn_mode
|
||||
|
||||
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.
|
||||
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
|
||||
instrumentation: [examples/afl_untracer/README.md](examples/afl_untracer/README.md)
|
||||
instrumentation: [utils/afl_untracer/README.md](utils/afl_untracer/README.md)
|
||||
|
||||
### More
|
||||
|
||||
@ -1037,7 +1038,7 @@ Here are some of the most important caveats for AFL:
|
||||
wholly wrap the actual data format to be tested.
|
||||
|
||||
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.
|
||||
See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use
|
||||
`AFL_CUSTOM_MUTATOR_LIBRARY`
|
||||
@ -1109,7 +1110,8 @@ without feedback, bug reports, or patches from:
|
||||
Andrea Biondo Vincent Le Garrec
|
||||
Khaled Yakdan Kuang-che Wu
|
||||
Josephine Calliotte Konrad Welc
|
||||
David Carlier Ruben ten Hove
|
||||
Thomas Rooijakkers David Carlier
|
||||
Ruben ten Hove
|
||||
```
|
||||
|
||||
Thank you!
|
||||
|
9
afl-cmin
9
afl-cmin
@ -113,14 +113,15 @@ function usage() {
|
||||
" -C - keep crashing inputs, reject everything else\n" \
|
||||
" -e - solve for edge coverage only, ignore hit counts\n" \
|
||||
"\n" \
|
||||
"For additional tips, please consult docs/README.md\n" \
|
||||
"For additional tips, please consult README.md\n" \
|
||||
"\n" \
|
||||
"Environment variables used:\n" \
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
"AFL_PATH: path for the afl-showmap 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"
|
||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ Minimization settings:
|
||||
-C - keep crashing inputs, reject everything else
|
||||
-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:
|
||||
AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
|
||||
|
@ -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
|
||||
excellent grammar custom mutator:
|
||||
```
|
||||
git submodule init
|
||||
git submodule update
|
||||
```sh
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
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
|
||||
it.
|
||||
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
||||
|
||||
## Production-Ready Custom Mutators
|
||||
|
||||
|
1
custom_mutators/grammar_mutator/GRAMMAR_VERSION
Normal file
1
custom_mutators/grammar_mutator/GRAMMAR_VERSION
Normal file
@ -0,0 +1 @@
|
||||
b3c4fcf
|
@ -1,17 +1,140 @@
|
||||
#!/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
|
||||
git stash ; git pull
|
||||
echo "================================================="
|
||||
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
|
||||
cd ..
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "All successfully prepared!"
|
||||
echo "To build for your grammar just do:"
|
||||
echo " cd Grammar_Mutator"
|
||||
echo "[+] All successfully prepared!"
|
||||
echo "[!] To build for your grammar just do:"
|
||||
echo " cd grammar-mutator"
|
||||
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
|
||||
|
1
custom_mutators/grammar_mutator/grammar_mutator
Submodule
1
custom_mutators/grammar_mutator/grammar_mutator
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b3c4fcfa6ae28918bc410f7747135eafd4fb7263
|
50
custom_mutators/grammar_mutator/update_grammar_ref.sh
Executable file
50
custom_mutators/grammar_mutator/update_grammar_ref.sh
Executable 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."
|
@ -1,7 +1,10 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "afl-fuzz.h"
|
||||
@ -21,6 +24,7 @@ typedef struct my_mutator {
|
||||
afl_state_t *afl;
|
||||
u8 * mutator_buf;
|
||||
u8 * out_dir;
|
||||
u8 * tmp_dir;
|
||||
u8 * target;
|
||||
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"))) {
|
||||
|
||||
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();
|
||||
|
||||
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))
|
||||
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);
|
||||
|
||||
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_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();
|
||||
|
||||
if (pid == -1) return;
|
||||
|
||||
if (pid) pid = waitpid(pid, NULL, 0);
|
||||
|
||||
if (pid == 0) {
|
||||
|
||||
setenv("SYMCC_INPUT_FILE", afl_struct->fsrv.out_file, 1);
|
||||
if (pid) {
|
||||
|
||||
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);
|
||||
|
||||
if (fd >= 0) {
|
||||
|
||||
ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
|
||||
close(fd);
|
||||
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);
|
||||
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);
|
||||
@ -130,6 +225,7 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
close(2);
|
||||
dup2(afl_struct->fsrv.dev_null_fd, 1);
|
||||
dup2(afl_struct->fsrv.dev_null_fd, 2);
|
||||
|
||||
execvp(data->target, afl_struct->argv);
|
||||
DBG("exec=FAIL\n");
|
||||
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;
|
||||
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;
|
||||
|
||||
@ -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);
|
||||
*out_buf = data->mutator_buf;
|
||||
|
||||
close(fd);
|
||||
done = 1;
|
||||
|
||||
@ -217,7 +314,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
|
||||
free(nl);
|
||||
DBG("FUZZ size=%lu\n", size);
|
||||
return size;
|
||||
return (uint32_t)size;
|
||||
|
||||
}
|
||||
|
||||
|
36
custom_mutators/symcc/test_examples/file_test.c
Normal file
36
custom_mutators/symcc/test_examples/file_test.c
Normal 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;
|
||||
|
||||
}
|
||||
|
28
custom_mutators/symcc/test_examples/stdin_test.c
Normal file
28
custom_mutators/symcc/test_examples/stdin_test.c
Normal 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;
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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
|
||||
conjunction with the -x option to allow the fuzzer to effortlessly explore the
|
||||
|
@ -11,6 +11,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
### Version ++3.00a (develop)
|
||||
- llvm_mode/ and gcc_plugin/ moved to instrumentation/
|
||||
- examples/ renamed to utils/
|
||||
- all compilers combined to afl-cc which emulates the previous ones
|
||||
- afl-llvm/gcc-rt.o merged into afl-compiler-rt.o
|
||||
- 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
|
||||
walk the whole queue approach. Select the old mode with -Z (auto enabled
|
||||
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 :)
|
||||
- not specifying -M or -S will now auto-set "-S default"
|
||||
- reading testcases from -i now descends into subdirectories
|
||||
- allow up to 4 times the -x command line option
|
||||
- loaded extras now have a duplicate protection
|
||||
- allow the -x command line option up to 4 times
|
||||
- loaded extras now have a duplication protection
|
||||
- If test cases are too large we do a partial read on the maximum
|
||||
supported size
|
||||
- longer seeds with the same trace information will now be ignored
|
||||
for fuzzing but still be used for splicing
|
||||
- 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
|
||||
- setting the env var AFL_NO_AUTODICT will not load an LTO autodictionary
|
||||
- added NO_SPLICING compile option and makefile define
|
||||
- added INTROSPECTION make target that writes all mutations to
|
||||
out/NAME/introspection.txt
|
||||
- added INTROSPECTION support for custom modules
|
||||
- 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
|
||||
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
||||
very much!!
|
||||
- not overriding -Ox or -fno-unroll-loops anymore
|
||||
- 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
|
||||
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
|
||||
-x dictionary of string comparisons found during compilation
|
||||
- LTO autodict now also collects interesting cmp comparisons,
|
||||
std::string compare + find + ==, bcmp
|
||||
- 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: libfuzzer that integrates libfuzzer mutations
|
||||
- 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)
|
||||
|
@ -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
|
||||
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.
|
||||
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
|
||||
desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) -
|
||||
|
@ -1 +0,0 @@
|
||||
../README.md
|
@ -15,7 +15,7 @@
|
||||
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.
|
||||
|
||||
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/.
|
||||
|
||||
@ -65,14 +65,14 @@
|
||||
## AFL FRIDA
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## AFL UNTRACER
|
||||
|
||||
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).
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@ C/C++:
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
@ -57,6 +58,9 @@ def fuzz_count(buf, add_buf, max_size):
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
return mutated_out
|
||||
|
||||
def describe(max_description_length):
|
||||
return "description_of_current_mutation"
|
||||
|
||||
def post_process(buf):
|
||||
return out_buf
|
||||
|
||||
@ -102,7 +106,7 @@ def introspection():
|
||||
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
|
||||
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):
|
||||
|
||||
@ -110,12 +114,19 @@ def introspection():
|
||||
additional test case.
|
||||
Note that this function is optional - but it makes sense to use it.
|
||||
You would only skip this if `post_process` is used to fix checksums etc.
|
||||
so 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` 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`
|
||||
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
|
||||
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):
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -210,19 +224,20 @@ Optionally, the following environment variables are supported:
|
||||
|
||||
- `AFL_PYTHON_ONLY`
|
||||
|
||||
Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead
|
||||
trimming can cause the same test breakage like havoc and splice.
|
||||
Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead.
|
||||
|
||||
- `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
|
||||
|
||||
### Prerequisite
|
||||
|
||||
For Python mutator, the python 3 or 2 development package is required. On
|
||||
Debian/Ubuntu/Kali this can be done:
|
||||
For Python mutators, the python 3 or 2 development package is required. On
|
||||
Debian/Ubuntu/Kali it can be installed like this:
|
||||
|
||||
```bash
|
||||
sudo apt install python3-dev
|
||||
@ -240,13 +255,13 @@ In case your setup is different, set the necessary variables like this:
|
||||
|
||||
### 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
|
||||
gcc -shared -Wall -O3 example.c -o example.so
|
||||
```
|
||||
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
|
||||
`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
|
||||
|
||||
@ -265,8 +280,8 @@ afl-fuzz /path/to/program
|
||||
|
||||
## 4) Example
|
||||
|
||||
Please see [example.c](../examples/custom_mutators/example.c) and
|
||||
[example.py](../examples/custom_mutators/example.py)
|
||||
Please see [example.c](../utils/custom_mutators/example.c) and
|
||||
[example.py](../utils/custom_mutators/example.py)
|
||||
|
||||
## 5) Other Resources
|
||||
|
||||
|
@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead:
|
||||
in your `$PATH`.
|
||||
|
||||
- `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
|
||||
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
|
||||
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
|
||||
queue. This can help with rare situations where a program crashes only
|
||||
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
|
||||
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.
|
||||
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
|
||||
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.
|
||||
Note that `AFL_DEBUG_CHILD_OUTPUT` is deprecated.
|
||||
|
||||
- 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.
|
||||
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
|
||||
fork + execve() call for every tested input. This is useful mostly when
|
||||
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.
|
||||
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:
|
||||
`AFL_DEFER_FORKSRV`
|
||||
`AFL_PERSISTENT`
|
||||
|
@ -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?
|
||||
|
||||
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?
|
||||
|
||||
Remove the checksum-checking code or use a postprocessor!
|
||||
See examples/custom_mutators/ for more.
|
||||
See utils/custom_mutators/ for more.
|
||||
|
||||
|
@ -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 .
|
||||
|
||||
- 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
|
||||
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
|
||||
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
|
||||
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
|
||||
avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for
|
||||
|
@ -152,7 +152,7 @@ write a simple script that performs two actions:
|
||||
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:
|
||||
* https://github.com/richo/roving
|
||||
|
Binary file not shown.
@ -113,6 +113,7 @@
|
||||
#include <kstat.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/pset.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#endif /* __linux__ */
|
||||
|
||||
@ -143,8 +144,8 @@ struct queue_entry {
|
||||
u8 *fname; /* File name for the test case */
|
||||
u32 len; /* Input length */
|
||||
|
||||
u8 cal_failed, /* Calibration failed? */
|
||||
trim_done, /* Trimmed? */
|
||||
u8 cal_failed; /* Calibration failed? */
|
||||
bool trim_done, /* Trimmed? */
|
||||
was_fuzzed, /* historical, but needed for MOpt */
|
||||
passed_det, /* Deterministic stages passed? */
|
||||
has_new_cov, /* Triggers new coverage? */
|
||||
@ -167,7 +168,8 @@ struct queue_entry {
|
||||
u8 *trace_mini; /* Trace bytes, if kept */
|
||||
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. */
|
||||
|
||||
@ -311,6 +313,7 @@ enum {
|
||||
/* 10 */ PY_FUNC_QUEUE_GET,
|
||||
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
|
||||
/* 12 */ PY_FUNC_INTROSPECTION,
|
||||
/* 13 */ PY_FUNC_DESCRIBE,
|
||||
PY_FUNC_COUNT
|
||||
|
||||
};
|
||||
@ -325,8 +328,7 @@ typedef struct py_mutator {
|
||||
u8 * fuzz_buf;
|
||||
size_t fuzz_size;
|
||||
|
||||
u8 * post_process_buf;
|
||||
size_t post_process_size;
|
||||
Py_buffer post_process_buf;
|
||||
|
||||
u8 * trim_buf;
|
||||
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,
|
||||
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_bench_until_crash, afl_debug_child_output, afl_autoresume,
|
||||
afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd;
|
||||
afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
|
||||
afl_cycle_schedules, afl_expand_havoc, afl_statsd;
|
||||
|
||||
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_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;
|
||||
|
||||
@ -754,7 +757,7 @@ struct custom_mutator {
|
||||
* When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can
|
||||
* 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*)
|
||||
*/
|
||||
const char *(*afl_custom_introspection)(void *data);
|
||||
@ -770,7 +773,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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_size Size of the test case
|
||||
* @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)
|
||||
*
|
||||
* @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
|
||||
* output
|
||||
* @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,
|
||||
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
|
||||
* 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
|
||||
* 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_size Size of the test case
|
||||
* @param[out] out_buf Pointer to the buffer storing the test case after
|
||||
@ -831,7 +849,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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_size Size of the test case
|
||||
* @return The amount of possible iteration steps to trim the input.
|
||||
@ -850,7 +868,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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.
|
||||
* The library can reuse a buffer for each call
|
||||
* and will have to free the buf (for example in deinit)
|
||||
@ -865,7 +883,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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.
|
||||
* @return The next trim iteration index (from 0 to the maximum amount of
|
||||
* steps returned in init_trim). Negative on error.
|
||||
@ -878,7 +896,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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
|
||||
* output
|
||||
* @param[in] buf_size Size of input data
|
||||
@ -897,7 +915,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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).
|
||||
*/
|
||||
u8 (*afl_custom_havoc_mutation_probability)(void *data);
|
||||
@ -907,7 +925,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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
|
||||
* @return Return True(1) if the fuzzer will fuzz the queue entry, and
|
||||
* False(0) otherwise.
|
||||
@ -920,7 +938,7 @@ struct custom_mutator {
|
||||
*
|
||||
* (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_orig_queue File name of the original queue entry. This
|
||||
* argument can be NULL while initializing the fuzzer
|
||||
@ -930,7 +948,7 @@ struct 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);
|
||||
|
||||
@ -1006,7 +1024,7 @@ void classify_counts(afl_forkserver_t *);
|
||||
void init_count_class16(void);
|
||||
void minimize_bits(afl_state_t *, u8 *, u8 *);
|
||||
#ifndef SIMPLE_FILES
|
||||
u8 *describe_op(afl_state_t *, u8);
|
||||
u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
|
@ -636,7 +636,7 @@ struct afl_alloc_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) {
|
||||
|
||||
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 */
|
||||
new_buf = (struct afl_alloc_buf *)realloc(new_buf, next_size);
|
||||
if (unlikely(!new_buf)) {
|
||||
struct afl_alloc_buf *newer_buf =
|
||||
(struct afl_alloc_buf *)realloc(new_buf, next_size);
|
||||
if (unlikely(!newer_buf)) {
|
||||
|
||||
free(new_buf); // avoid a leak
|
||||
*buf = NULL;
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = newer_buf;
|
||||
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
/* alloc */
|
||||
new_buf = (struct afl_alloc_buf *)realloc(new_buf, size_needed);
|
||||
if (unlikely(!new_buf)) {
|
||||
struct afl_alloc_buf *newer_buf =
|
||||
(struct afl_alloc_buf *)realloc(new_buf, size_needed);
|
||||
if (unlikely(!newer_buf)) {
|
||||
|
||||
free(new_buf); // avoid a leak
|
||||
*buf = NULL;
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = newer_buf;
|
||||
|
||||
}
|
||||
|
||||
new_buf->complete_size = size_needed;
|
||||
|
@ -31,14 +31,14 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
|
||||
|
||||
#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);
|
||||
|
||||
char **argv_cpy_dup(int argc, char **argv);
|
||||
|
@ -270,6 +270,16 @@
|
||||
\
|
||||
} 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
|
||||
appropriate. */
|
||||
|
||||
|
@ -6,6 +6,7 @@ static char *afl_environment_deprecated[] = {
|
||||
|
||||
"AFL_LLVM_WHITELIST",
|
||||
"AFL_GCC_WHITELIST",
|
||||
"AFL_DEBUG_CHILD_OUTPUT",
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PERSISTENT",
|
||||
@ -31,12 +32,13 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CODE_START",
|
||||
"AFL_COMPCOV_BINNAME",
|
||||
"AFL_COMPCOV_LEVEL",
|
||||
"AFL_CRASH_EXITCODE",
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"AFL_CXX",
|
||||
"AFL_CYCLE_SCHEDULES",
|
||||
"AFL_DEBUG",
|
||||
"AFL_DEBUG_CHILD_OUTPUT",
|
||||
"AFL_DEBUG_CHILD",
|
||||
"AFL_DEBUG_GDB",
|
||||
"AFL_DISABLE_TRIM",
|
||||
"AFL_DONT_OPTIMIZE",
|
||||
@ -99,6 +101,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_LLVM_LTO_STARTID",
|
||||
"AFL_LLVM_LTO_DONTWRITEID",
|
||||
"AFL_NO_ARITH",
|
||||
"AFL_NO_AUTODICT",
|
||||
"AFL_NO_BUILTIN",
|
||||
"AFL_NO_CPU_RED",
|
||||
"AFL_NO_FORKSRV",
|
||||
@ -123,6 +126,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR",
|
||||
"AFL_QEMU_PERSISTENT_HOOK",
|
||||
"AFL_QEMU_PERSISTENT_MEM",
|
||||
"AFL_QEMU_PERSISTENT_RET",
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
|
||||
"AFL_QEMU_PERSISTENT_EXITS",
|
||||
|
@ -37,9 +37,7 @@ typedef struct afl_forkserver {
|
||||
|
||||
/* a program that includes afl-forkserver needs to define these */
|
||||
|
||||
u8 uses_asan; /* Target uses ASAN? */
|
||||
u8 *trace_bits; /* SHM with instrumentation bitmap */
|
||||
u8 use_stdin; /* use stdin for sending data */
|
||||
|
||||
s32 fsrv_pid, /* PID of the fork server */
|
||||
child_pid, /* PID of the fuzzed program */
|
||||
@ -53,8 +51,6 @@ typedef struct afl_forkserver {
|
||||
fsrv_ctl_fd, /* Fork server control pipe (write) */
|
||||
fsrv_st_fd; /* Fork server status pipe (read) */
|
||||
|
||||
u8 no_unlink; /* do not unlink cur_input */
|
||||
|
||||
u32 exec_tmout; /* Configurable exec timeout (ms) */
|
||||
u32 init_tmout; /* Configurable init timeout (ms) */
|
||||
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 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 */
|
||||
|
||||
|
@ -268,8 +268,8 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
for (auto &BB : F)
|
||||
if (BB.size() > 0) ++bb_cnt;
|
||||
SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n",
|
||||
F.getName().str().c_str(), F.size(), bb_cnt);
|
||||
DEBUGF("Function %s size %zu %u\n", F.getName().str().c_str(), F.size(),
|
||||
bb_cnt);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
afl-clang-fast; #ifdef guards can be used to suppress it when using other
|
||||
compilers.
|
||||
|
@ -60,7 +60,12 @@ AUTODICTIONARY: 11 strings found
|
||||
|
||||
## 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:
|
||||
|
||||
@ -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 -
|
||||
apt-get update && apt-get upgrade -y
|
||||
apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
|
||||
libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \
|
||||
libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \
|
||||
liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \
|
||||
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
|
||||
apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools
|
||||
```
|
||||
|
||||
### 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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
On unusual operating systems/processors/kernels or weird libraries this might
|
||||
fail so to change the fixed address at compile time set
|
||||
AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address
|
||||
to be dynamic - the original afl way, which is slower).
|
||||
|
||||
Also on unusual operating systems/processors/kernels or weird libraries the
|
||||
recommended 0x10000 address might not work, so then change the fixed address.
|
||||
|
||||
To enable this feature set AFL_LLVM_MAP_ADDR with the address.
|
||||
|
||||
## Document edge IDs
|
||||
|
||||
|
@ -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
|
||||
(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;
|
||||
|
||||
@ -23,15 +23,20 @@ __AFL_FUZZ_INIT();
|
||||
|
||||
main() {
|
||||
|
||||
// anything else here, eg. command line arguments, initialization, etc.
|
||||
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
__AFL_INIT();
|
||||
#endif
|
||||
|
||||
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT
|
||||
// and before __AFL_LOOP!
|
||||
|
||||
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
|
||||
|
||||
/* 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
|
||||
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
|
||||
*not* generate a deferred-initialization binary) - and you should be all set!
|
||||
Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast
|
||||
(afl-gcc or afl-clang will *not* generate a deferred-initialization binary) -
|
||||
and you should be all set!
|
||||
|
||||
*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
|
||||
|
||||
@ -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
|
||||
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
|
||||
guards can be used to suppress it when using other compilers.
|
||||
|
||||
|
@ -544,7 +544,9 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
be_quiet = 1;
|
||||
|
||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||
// scanForDangerousFunctions(&M);
|
||||
|
||||
initInstrumentList();
|
||||
scanForDangerousFunctions(&M);
|
||||
|
||||
if (debug) {
|
||||
|
||||
@ -819,6 +821,8 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
||||
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
|
||||
|
||||
if (F.empty()) return;
|
||||
if (!isInInstrumentList(&F)) return;
|
||||
|
||||
if (F.getName().find(".module_ctor") != std::string::npos)
|
||||
return; // Should not instrument sanitizer init functions.
|
||||
if (F.getName().startswith("__sanitizer_"))
|
||||
@ -1123,11 +1127,11 @@ void ModuleSanitizerCoverage::InjectTraceForCmp(
|
||||
Value * A1 = ICMP->getOperand(1);
|
||||
if (!A0->getType()->isIntegerTy()) continue;
|
||||
uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType());
|
||||
int CallbackIdx =
|
||||
TypeSize == 8
|
||||
? 0
|
||||
int CallbackIdx = TypeSize == 8 ? 0
|
||||
: TypeSize == 16 ? 1
|
||||
: TypeSize == 32 ? 2 : TypeSize == 64 ? 3 : -1;
|
||||
: TypeSize == 32 ? 2
|
||||
: TypeSize == 64 ? 3
|
||||
: -1;
|
||||
if (CallbackIdx < 0) continue;
|
||||
// __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1);
|
||||
auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx];
|
||||
@ -1315,6 +1319,7 @@ std::string ModuleSanitizerCoverage::getSectionEnd(
|
||||
}
|
||||
|
||||
char ModuleSanitizerCoverageLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
|
||||
"Pass for instrumenting coverage on functions", false,
|
||||
false)
|
||||
@ -1323,6 +1328,7 @@ INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
|
||||
INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
|
||||
"Pass for instrumenting coverage on functions", false,
|
||||
false)
|
||||
|
||||
ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
|
||||
const SanitizerCoverageOptions &Options,
|
||||
const std::vector<std::string> &AllowlistFiles,
|
||||
|
@ -101,6 +101,11 @@ int __afl_sharedmem_fuzzing __attribute__((weak));
|
||||
|
||||
struct cmp_map *__afl_cmp_map;
|
||||
|
||||
/* Child pid? */
|
||||
|
||||
static s32 child_pid;
|
||||
static void (*old_sigterm_handler)(int) = 0;
|
||||
|
||||
/* Running in persistent mode? */
|
||||
|
||||
static u8 is_persistent;
|
||||
@ -109,6 +114,14 @@ static u8 is_persistent;
|
||||
|
||||
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 */
|
||||
|
||||
void __afl_trace(const u32 x) {
|
||||
@ -150,6 +163,12 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
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) {
|
||||
|
||||
u8 *map = NULL;
|
||||
@ -182,7 +201,8 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@ -199,6 +219,7 @@ static void __afl_map_shm_fuzz() {
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -322,6 +343,8 @@ static void __afl_map_shm(void) {
|
||||
send_forkserver_error(FS_ERROR_MAP_ADDR);
|
||||
else
|
||||
send_forkserver_error(FS_ERROR_MMAP);
|
||||
perror("mmap for map");
|
||||
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -332,20 +355,22 @@ static void __afl_map_shm(void) {
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0);
|
||||
|
||||
#endif
|
||||
|
||||
/* Whooooops. */
|
||||
|
||||
if (__afl_area_ptr == (void *)-1) {
|
||||
if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
|
||||
|
||||
if (__afl_map_addr)
|
||||
send_forkserver_error(FS_ERROR_MAP_ADDR);
|
||||
else
|
||||
send_forkserver_error(FS_ERROR_SHMAT);
|
||||
|
||||
perror("shmat for map");
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Write something into the bitmap so that even with low AFL_INST_RATIO,
|
||||
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",
|
||||
(void *)__afl_map_addr);
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -397,7 +423,8 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
perror("shm_open() failed\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -411,6 +438,7 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -422,7 +450,13 @@ static void __afl_map_shm(void) {
|
||||
__afl_cmp_map = shmat(shm_id, NULL, 0);
|
||||
#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 u8 tmp[4] = {0, 0, 0, 0};
|
||||
s32 child_pid;
|
||||
u32 status = 0;
|
||||
u32 already_read_first = 0;
|
||||
u32 was_killed;
|
||||
@ -579,6 +612,7 @@ static void __afl_start_snapshots(void) {
|
||||
//(void)nice(-20); // does not seem to improve
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
signal(SIGTERM, old_sigterm_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
@ -633,6 +667,11 @@ static void __afl_start_snapshots(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__
|
||||
if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
|
||||
afl_snapshot_init() >= 0) {
|
||||
@ -645,7 +684,6 @@ static void __afl_start_forkserver(void) {
|
||||
#endif
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
s32 child_pid;
|
||||
u32 status = 0;
|
||||
u32 already_read_first = 0;
|
||||
u32 was_killed;
|
||||
@ -793,6 +831,7 @@ static void __afl_start_forkserver(void) {
|
||||
//(void)nice(-20);
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
signal(SIGTERM, old_sigterm_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
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
|
||||
// edge IDs belong - uncomment, recompile+install llvm_mode, recompile
|
||||
// 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
|
||||
/*
|
||||
uint32_t unstable[] = { ... unstable edge IDs };
|
||||
|
@ -627,8 +627,7 @@ struct afl_pass : gimple_opt_pass {
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded allowlist with %zu file and %zu function entries\n",
|
||||
DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
|
||||
allowListFiles.size(), allowListFunctions.size());
|
||||
|
||||
}
|
||||
@ -702,8 +701,7 @@ struct afl_pass : gimple_opt_pass {
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded denylist with %zu file and %zu function entries\n",
|
||||
DEBUGF("loaded denylist with %zu file and %zu function entries\n",
|
||||
denyListFiles.size(), denyListFunctions.size());
|
||||
|
||||
}
|
||||
@ -745,9 +743,9 @@ struct afl_pass : gimple_opt_pass {
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the deny function list, "
|
||||
"not instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the deny function list, not "
|
||||
"instrumenting ... \n",
|
||||
instFunction.c_str());
|
||||
return false;
|
||||
|
||||
@ -825,9 +823,9 @@ struct afl_pass : gimple_opt_pass {
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allow function list, "
|
||||
"instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the allow function list, instrumenting "
|
||||
"... \n",
|
||||
instFunction.c_str());
|
||||
return true;
|
||||
|
||||
@ -859,9 +857,9 @@ struct afl_pass : gimple_opt_pass {
|
||||
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allowlist (%s), "
|
||||
"instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the allowlist (%s), instrumenting ... "
|
||||
"\n",
|
||||
IDENTIFIER_POINTER(DECL_NAME(F->decl)),
|
||||
source_file.c_str());
|
||||
return true;
|
||||
|
@ -173,8 +173,7 @@ void initInstrumentList() {
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded allowlist with %zu file and %zu function entries\n",
|
||||
DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
|
||||
allowListFiles.size(), allowListFunctions.size());
|
||||
|
||||
}
|
||||
@ -248,8 +247,7 @@ void initInstrumentList() {
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded denylist with %zu file and %zu function entries\n",
|
||||
DEBUGF("loaded denylist with %zu file and %zu function entries\n",
|
||||
denyListFiles.size(), denyListFunctions.size());
|
||||
|
||||
}
|
||||
@ -409,9 +407,9 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the deny function list, "
|
||||
"not instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the deny function list, not instrumenting "
|
||||
"... \n",
|
||||
instFunction.c_str());
|
||||
return false;
|
||||
|
||||
@ -489,9 +487,9 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allow function list, "
|
||||
"instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the allow function list, instrumenting "
|
||||
"... \n",
|
||||
instFunction.c_str());
|
||||
return true;
|
||||
|
||||
@ -523,9 +521,9 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allowlist (%s), "
|
||||
"instrumenting ... \n",
|
||||
DEBUGF(
|
||||
"Function %s is in the allowlist (%s), instrumenting ... "
|
||||
"\n",
|
||||
F->getName().str().c_str(), source_file.c_str());
|
||||
return true;
|
||||
|
||||
|
@ -105,14 +105,13 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
|
||||
if (isInInstrumentList(&F)) {
|
||||
|
||||
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());
|
||||
|
||||
} else {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"function %s is NOT in the instrument file list\n",
|
||||
DEBUGF("function %s is NOT in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
auto & Ctx = F.getContext();
|
||||
|
@ -601,11 +601,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; }
|
||||
|
||||
const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits();
|
||||
const unsigned int precision =
|
||||
sizeInBits == 32
|
||||
? 24
|
||||
: sizeInBits == 64
|
||||
? 53
|
||||
const unsigned int precision = sizeInBits == 32 ? 24
|
||||
: sizeInBits == 64 ? 53
|
||||
: sizeInBits == 128 ? 113
|
||||
: sizeInBits == 16 ? 11
|
||||
/* sizeInBits == 80 */
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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
|
||||
libc allocator in the fuzzed binaries. It improves the odds of bumping into
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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()`,
|
||||
and related functions to automatically extract syntax tokens passed to any of
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@ -179,7 +179,7 @@ match.
|
||||
## 12) Gotchas, feedback, bugs
|
||||
|
||||
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
|
||||
the "shadow VM" trick employed by the sanitizers and will probably just
|
||||
|
@ -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.
|
||||
|
||||
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)
|
||||
|
@ -114,7 +114,7 @@ git status 1>/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[*] initializing qemuafl submodule"
|
||||
git submodule init || exit 1
|
||||
git submodule update 2>/dev/null # ignore errors
|
||||
git submodule update ./qemuafl 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning qemuafl"
|
||||
test -d qemuafl || {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit d66c9e2654efa8939f0fe6995d11a72b98a4da3e
|
||||
Subproject commit 21ff34383764a8c6f66509b3b8d5282468c721e1
|
@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
|
||||
|
||||
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_stdin = 1; /* Use stdin for program input? */
|
||||
use_stdin = true; /* Use stdin for program input? */
|
||||
|
||||
static volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||
child_timed_out; /* Child timed out? */
|
||||
|
@ -27,7 +27,7 @@
|
||||
utility has right now is to be able to skip them gracefully and allow the
|
||||
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
|
||||
note that there is no equivalent for GCC.
|
||||
|
||||
|
381
src/afl-cc.c
381
src/afl-cc.c
@ -48,10 +48,11 @@
|
||||
static u8 * obj_path; /* Path to runtime libraries */
|
||||
static u8 **cc_params; /* Parameters passed to the real CC */
|
||||
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 instrument_mode, instrument_opt_mode, ngram_size, lto_mode,
|
||||
compiler_mode, plusplus_mode;
|
||||
static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto;
|
||||
static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode;
|
||||
static u8 compiler_mode, plusplus_mode, have_instr_env = 0;
|
||||
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 debug;
|
||||
static u8 cwd[4096];
|
||||
@ -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) {
|
||||
|
||||
u8 *afl_path = getenv("AFL_PATH");
|
||||
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) {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
tmp = alloc_printf("%s/%s", afl_path, obj);
|
||||
#else
|
||||
tmp = alloc_printf("%s/%s", afl_path, obj);
|
||||
#endif
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
@ -131,101 +155,35 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
|
||||
|
||||
}
|
||||
|
||||
if (argv0) slash = strrchr(argv0, '/');
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8 *dir;
|
||||
|
||||
*slash = 0;
|
||||
dir = ck_strdup(argv0);
|
||||
*slash = '/';
|
||||
|
||||
#ifdef __ANDROID__
|
||||
tmp = alloc_printf("%s/%s", dir, obj);
|
||||
#else
|
||||
tmp = alloc_printf("%s/%s", dir, obj);
|
||||
#endif
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = dir;
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
ck_free(dir);
|
||||
|
||||
}
|
||||
|
||||
tmp = alloc_printf("%s/%s", AFL_PATH, obj);
|
||||
#ifdef __ANDROID__
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
#else
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
#endif
|
||||
|
||||
obj_path = AFL_PATH;
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
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);
|
||||
|
||||
}
|
||||
if (argv0) {
|
||||
|
||||
slash = strrchr(argv0, '/');
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8 *dir;
|
||||
u8 *dir = ck_strdup(argv0);
|
||||
|
||||
slash = strrchr(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
|
||||
tmp = alloc_printf("%s/%s", dir, obj);
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = dir;
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
return;
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@ -234,22 +192,90 @@ static void find_obj(u8 *argv0) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (!access(AFL_PATH "/afl-compiler-rt.so", R_OK)) {
|
||||
|
||||
#else
|
||||
if (!access(AFL_PATH "/afl-compiler-rt.o", R_OK)) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
|
||||
defined(__ANDROID__) || defined(__NetBSD__)
|
||||
#define HAS_PROC_FS 1
|
||||
#endif
|
||||
#ifdef HAS_PROC_FS
|
||||
else {
|
||||
|
||||
obj_path = AFL_PATH;
|
||||
return;
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
FATAL(
|
||||
"Unable to find 'afl-compiler-rt.o' or 'afl-llvm-pass.so'. Please set "
|
||||
"AFL_PATH");
|
||||
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);
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = AFL_PATH;
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
tmp = alloc_printf("./%s", obj);
|
||||
|
||||
if (!access(tmp, R_OK)) {
|
||||
|
||||
obj_path = ".";
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
@ -288,8 +314,16 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
if (compiler_mode >= GCC_PLUGIN) {
|
||||
|
||||
if (compiler_mode == GCC) {
|
||||
|
||||
alt_cxx = clang_mode ? "clang++" : "g++";
|
||||
|
||||
} else {
|
||||
|
||||
alt_cxx = "g++";
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (USE_BINDIR)
|
||||
@ -313,8 +347,16 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
if (compiler_mode >= GCC_PLUGIN) {
|
||||
|
||||
if (compiler_mode == GCC) {
|
||||
|
||||
alt_cc = clang_mode ? "clang" : "gcc";
|
||||
|
||||
} else {
|
||||
|
||||
alt_cc = "gcc";
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (USE_BINDIR)
|
||||
@ -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++] = obj_path;
|
||||
|
||||
if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; }
|
||||
|
||||
}
|
||||
|
||||
if (compiler_mode == GCC_PLUGIN) {
|
||||
|
||||
char *fplugin_arg =
|
||||
alloc_printf("-fplugin=%s", find_object("afl-gcc-pass.so", argvnull));
|
||||
char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] = fplugin_arg;
|
||||
|
||||
}
|
||||
@ -354,11 +397,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
if (lto_mode && plusplus_mode)
|
||||
cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early
|
||||
|
||||
if (lto_mode) {
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
|
||||
if (lto_mode && have_instr_env) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
@ -368,8 +407,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_DICT2FILE")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
@ -508,11 +545,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD) {
|
||||
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
if (have_instr_list) {
|
||||
|
||||
if (!be_quiet)
|
||||
SAYF(
|
||||
"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
|
||||
#if LLVM_MAJOR >= 4
|
||||
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, "-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"))
|
||||
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") ||
|
||||
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-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)
|
||||
cc_params[cc_par_cnt++] =
|
||||
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;
|
||||
|
||||
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;
|
||||
argvnull = (u8 *)argv[0];
|
||||
check_environment_vars(envp);
|
||||
@ -915,7 +978,9 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
} 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;
|
||||
|
||||
@ -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++) {
|
||||
|
||||
if (strncmp(argv[i], "--afl", 5) == 0) {
|
||||
@ -1015,22 +1088,21 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) &&
|
||||
getenv("AFL_DONT_OPTIMIZE"))
|
||||
if (have_instr_env && getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
WARNF(
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
|
||||
"for file matching, only function matching!");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
|
||||
getenv("INSTRIM_LIB")) {
|
||||
|
||||
if (instrument_mode == 0)
|
||||
instrument_mode = INSTRUMENT_CFG;
|
||||
else if (instrument_mode != INSTRUMENT_CFG)
|
||||
FATAL(
|
||||
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
|
||||
FATAL("you cannot 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 "
|
||||
"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)
|
||||
SAYF(
|
||||
"\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
|
||||
"variables:\n"
|
||||
#if LLVM_MAJOR < 9
|
||||
" AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
|
||||
#else
|
||||
" AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
|
||||
#endif
|
||||
|
||||
COUNTER_BEHAVIOUR
|
||||
|
||||
" AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
|
||||
"comparisons\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
|
||||
instrument_mode = INSTRUMENT_AFL;
|
||||
#else
|
||||
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
|
||||
#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
|
||||
if (have_instr_env) {
|
||||
|
||||
instrument_mode = INSTRUMENT_AFL;
|
||||
if (!be_quiet)
|
||||
WARNF(
|
||||
"switching to classic instrumentation because "
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use "
|
||||
"-fsanitize-coverage-allowlist=allowlist.txt or "
|
||||
"-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");
|
||||
"Switching to classic instrumentation because "
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
|
||||
|
||||
} else
|
||||
|
||||
#endif
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
|
||||
#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 "
|
||||
"together");
|
||||
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD &&
|
||||
(getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")))
|
||||
#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD && have_instr_env) {
|
||||
|
||||
FATAL(
|
||||
"Instrumentation type PCGUARD does not support "
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST! Use "
|
||||
"-fsanitize-coverage-allowlist=allowlist.txt or "
|
||||
"-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm "
|
||||
"12+), see "
|
||||
"https://clang.llvm.org/docs/"
|
||||
"SanitizerCoverage.html#partially-disabling-instrumentation");
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
u8 *ptr2;
|
||||
|
||||
@ -1525,7 +1598,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd());
|
||||
DEBUGF("cd '%s';", getthecwd());
|
||||
for (i = 0; i < argc; i++)
|
||||
SAYF(" '%s'", argv[i]);
|
||||
SAYF("\n");
|
||||
@ -1545,15 +1618,29 @@ int main(int argc, char **argv, char **envp) {
|
||||
if (!be_quiet && cmplog_mode)
|
||||
printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
|
||||
|
||||
#ifndef __ANDROID__
|
||||
find_obj(argv[0]);
|
||||
#ifdef __ANDROID__
|
||||
ptr = find_object("afl-compiler-rt.so", argv[0]);
|
||||
#else
|
||||
ptr = find_object("afl-compiler-rt.o", argv[0]);
|
||||
#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);
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd());
|
||||
DEBUGF("cd '%s';", getthecwd());
|
||||
for (i = 0; i < (s32)cc_par_cnt; i++)
|
||||
SAYF(" '%s'", cc_params[i]);
|
||||
SAYF("\n");
|
||||
|
@ -46,7 +46,7 @@ u8 be_quiet = 0;
|
||||
u8 *doc_path = "";
|
||||
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;
|
||||
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."); }
|
||||
|
||||
*use_stdin = 0;
|
||||
*use_stdin = false;
|
||||
|
||||
if (prog_in[0] != 0) { // not afl-showmap special case
|
||||
|
||||
|
@ -62,6 +62,7 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
WARNF("Execv failed in forkserver.");
|
||||
}
|
||||
|
||||
/* Initializes the struct */
|
||||
@ -76,8 +77,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
fsrv->dev_urandom_fd = -1;
|
||||
|
||||
/* Settings */
|
||||
fsrv->use_stdin = 1;
|
||||
fsrv->no_unlink = 0;
|
||||
fsrv->use_stdin = true;
|
||||
fsrv->no_unlink = false;
|
||||
fsrv->exec_tmout = EXEC_TIMEOUT;
|
||||
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
|
||||
fsrv->mem_limit = MEM_LIMIT;
|
||||
@ -86,8 +87,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
/* exec related stuff */
|
||||
fsrv->child_pid = -1;
|
||||
fsrv->map_size = get_map_size();
|
||||
fsrv->use_fauxsrv = 0;
|
||||
fsrv->last_run_timed_out = 0;
|
||||
fsrv->use_fauxsrv = false;
|
||||
fsrv->last_run_timed_out = false;
|
||||
|
||||
fsrv->uses_crash_exitcode = false;
|
||||
fsrv->uses_asan = false;
|
||||
|
||||
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->out_fd = from->out_fd; // not sure this is a good idea
|
||||
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.
|
||||
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->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
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
|
||||
// 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. */
|
||||
|
||||
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.");
|
||||
break;
|
||||
default:
|
||||
FATAL("unknown error code %u from fuzzing target!", error);
|
||||
FATAL("unknown error code %d from fuzzing target!", error);
|
||||
|
||||
}
|
||||
|
||||
@ -350,12 +357,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
int st_pipe[2], ctl_pipe[2];
|
||||
s32 status;
|
||||
s32 rlen;
|
||||
char *ignore_autodict = getenv("AFL_NO_AUTODICT");
|
||||
|
||||
if (!be_quiet) { ACTF("Spinning up the fork server..."); }
|
||||
|
||||
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) {
|
||||
|
||||
@ -519,8 +527,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
falling through. */
|
||||
|
||||
*(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
|
||||
fprintf(stderr, "Error: execv to target failed\n");
|
||||
exit(0);
|
||||
FATAL("Error: execv to target failed\n");
|
||||
|
||||
}
|
||||
|
||||
@ -606,7 +613,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
fsrv->use_shmem_fuzz = 1;
|
||||
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);
|
||||
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
|
||||
@ -659,6 +666,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
|
||||
|
||||
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
|
||||
@ -758,6 +771,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -901,7 +916,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
" estimate the required amount of virtual memory for the "
|
||||
"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"
|
||||
" instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
|
||||
"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 (*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?)");
|
||||
|
||||
}
|
||||
@ -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
|
||||
must use a special exit code. */
|
||||
/* MSAN in uses_asan mode uses a special exit code as it doesn't support
|
||||
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;
|
||||
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.
|
||||
// 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;
|
||||
|
||||
|
@ -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
|
||||
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;
|
||||
|
||||
if (unlikely(afl->syncing_party)) {
|
||||
@ -445,6 +447,38 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
|
||||
|
||||
sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
|
||||
|
||||
if (afl->current_custom_fuzz &&
|
||||
afl->current_custom_fuzz->afl_custom_describe) {
|
||||
|
||||
/* We are currently in a custom mutator that supports afl_custom_describe,
|
||||
* use it! */
|
||||
|
||||
size_t len_current = strlen(ret);
|
||||
ret[len_current++] = ',';
|
||||
ret[len_current] = '\0';
|
||||
|
||||
ssize_t size_left = real_max_len - len_current - strlen(",+cov") - 2;
|
||||
if (unlikely(size_left <= 0)) FATAL("filename got too long");
|
||||
|
||||
const char *custom_description =
|
||||
afl->current_custom_fuzz->afl_custom_describe(
|
||||
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 {
|
||||
|
||||
/* Normal testcase descriptions start here */
|
||||
sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
|
||||
|
||||
if (afl->stage_cur_byte >= 0) {
|
||||
@ -467,7 +501,12 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -540,7 +579,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
if (unlikely(len == 0)) { return 0; }
|
||||
|
||||
u8 *queue_fn = "";
|
||||
u8 hnb = '\0';
|
||||
u8 new_bits = '\0';
|
||||
s32 fd;
|
||||
u8 keeping = 0, res;
|
||||
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
|
||||
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; }
|
||||
return 0;
|
||||
@ -575,8 +614,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
#ifndef SIMPLE_FILES
|
||||
|
||||
queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir,
|
||||
afl->queued_paths, describe_op(afl, hnb));
|
||||
queue_fn = alloc_printf(
|
||||
"%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths,
|
||||
describe_op(afl, new_bits, NAME_MAX - strlen("id:000000,")));
|
||||
|
||||
#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);
|
||||
|
||||
#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);
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
@ -616,7 +659,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
#endif
|
||||
|
||||
if (hnb == 2) {
|
||||
if (new_bits == 2) {
|
||||
|
||||
afl->queue_top->has_new_cov = 1;
|
||||
++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)) {
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@ -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,
|
||||
afl->unique_crashes, afl->fsrv.last_kill_signal,
|
||||
describe_op(afl, 0));
|
||||
describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")));
|
||||
|
||||
#else
|
||||
|
||||
|
@ -355,7 +355,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
|
||||
|
||||
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);
|
||||
if (kstat_read(m, k, &cs)) {
|
||||
@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
if (skip_crashes) {
|
||||
|
||||
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;
|
||||
++cal_failures;
|
||||
break;
|
||||
@ -954,8 +966,19 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
#undef MSG_ULIMIT_USAGE
|
||||
#undef MSG_FORK_ON_APPLE
|
||||
|
||||
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 */
|
||||
|
||||
struct queue_entry *p = afl->queue;
|
||||
@ -2300,12 +2323,6 @@ void fix_up_sync(afl_state_t *afl) {
|
||||
|
||||
u8 *x = afl->sync_id;
|
||||
|
||||
if (afl->non_instrumented_mode) {
|
||||
|
||||
FATAL("-S / -M and -n are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
while (*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;
|
||||
|
||||
|
@ -151,7 +151,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
|
||||
/* Mutator */
|
||||
/* "afl_custom_init", optional for backward compatibility */
|
||||
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 */
|
||||
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'.");
|
||||
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_introspection", optional */
|
||||
#ifdef 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.");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* "afl_custom_fuzz_count", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_deinit", optional for backward compatibility */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_post_process", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
u8 notrim = 0;
|
||||
/* "afl_custom_init_trim", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_trim", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_post_trim", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
if (notrim) {
|
||||
|
||||
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 */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_havoc_mutation", optional */
|
||||
mutator->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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_queue_get", optional */
|
||||
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.");
|
||||
|
||||
}
|
||||
|
||||
/* "afl_custom_queue_new_entry", optional */
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
/* "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);
|
||||
|
||||
/* 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->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
|
||||
mutator->stacked_custom_prob =
|
||||
6; // like one of the default mutations in havoc
|
||||
|
@ -445,8 +445,13 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(afl->not_on_tty)) {
|
||||
|
||||
ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...",
|
||||
afl->current_entry, afl->queued_paths, afl->unique_crashes);
|
||||
ACTF(
|
||||
"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);
|
||||
|
||||
}
|
||||
@ -1790,11 +1795,16 @@ custom_mutator_stage:
|
||||
|
||||
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);
|
||||
else
|
||||
|
||||
} else {
|
||||
|
||||
afl->stage_max = saved_max;
|
||||
|
||||
}
|
||||
|
||||
has_custom_fuzz = true;
|
||||
|
||||
afl->stage_short = el->name_short;
|
||||
|
@ -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);
|
||||
|
||||
*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);
|
||||
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) {
|
||||
|
||||
(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_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) {
|
||||
|
||||
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");
|
||||
if (!py_functions[PY_FUNC_FUZZ])
|
||||
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] =
|
||||
PyObject_GetAttrString(py_module, "fuzz_count");
|
||||
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;
|
||||
|
||||
mutator = ck_alloc(sizeof(struct custom_mutator));
|
||||
mutator->post_process_buf = NULL;
|
||||
|
||||
mutator->name = 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; }
|
||||
|
||||
/* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
|
||||
is quite different from the custom mutator. */
|
||||
mutator->afl_custom_fuzz = fuzz_py;
|
||||
if (py_functions[PY_FUNC_FUZZ]) { 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]) {
|
||||
|
||||
@ -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,
|
||||
u8 **out_buf) {
|
||||
|
||||
size_t py_out_buf_size;
|
||||
PyObject * py_args, *py_value;
|
||||
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_value = PyByteArray_FromStringAndSize(buf, buf_size);
|
||||
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) {
|
||||
|
||||
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))) {
|
||||
|
||||
PFATAL("alloc");
|
||||
PyErr_Print();
|
||||
FATAL(
|
||||
"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);
|
||||
|
||||
*out_buf = py->post_process_buf;
|
||||
return py_out_buf_size;
|
||||
*out_buf = (u8 *)py->post_process_buf.buf;
|
||||
return py->post_process_buf.len;
|
||||
|
||||
} else {
|
||||
|
||||
@ -581,7 +632,7 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
|
||||
|
||||
ret = PyByteArray_Size(py_value);
|
||||
*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);
|
||||
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... */
|
||||
*out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size);
|
||||
if (unlikely(!out_buf)) { PFATAL("alloc"); }
|
||||
if (unlikely(!*out_buf)) { PFATAL("alloc"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
void create_alias_table(afl_state_t *afl) {
|
||||
|
||||
u32 n = afl->queued_paths, i = 0, a, g;
|
||||
double sum = 0;
|
||||
|
||||
afl->alias_table =
|
||||
(u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
|
||||
@ -56,11 +74,52 @@ void create_alias_table(afl_state_t *afl) {
|
||||
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));
|
||||
|
||||
if (!P || !S || !L) { FATAL("could not aquire memory for alias table"); }
|
||||
if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
|
||||
|
||||
FATAL("could not acquire memory for alias table");
|
||||
|
||||
}
|
||||
|
||||
memset((void *)afl->alias_table, 0, n * sizeof(u32));
|
||||
memset((void *)afl->alias_probability, 0, n * sizeof(double));
|
||||
|
||||
double sum = 0;
|
||||
if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
|
||||
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++) {
|
||||
|
||||
@ -79,6 +138,8 @@ void create_alias_table(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int nS = 0, nL = 0, s;
|
||||
for (s = (s32)n - 1; s >= 0; --s) {
|
||||
|
||||
|
@ -79,7 +79,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
|
||||
s32 doc_fd;
|
||||
char fn[PATH_MAX];
|
||||
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) {
|
||||
|
||||
@ -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->afl_env.afl_debug_child_output);
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
|
||||
|
||||
@ -484,7 +485,7 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
DIR * sd;
|
||||
struct dirent *sd_ent;
|
||||
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);
|
||||
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
|
||||
@ -590,7 +591,7 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
while (m < n) {
|
||||
|
||||
if (strcmp(namelist[m]->d_name, entry)) {
|
||||
if (strncmp(namelist[m]->d_name, entry, 9)) {
|
||||
|
||||
m++;
|
||||
|
||||
|
@ -268,11 +268,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
|
||||
afl->afl_env.afl_bench_until_crash =
|
||||
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->afl_env.afl_debug_child_output =
|
||||
afl->afl_env.afl_debug_child =
|
||||
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
|
||||
|
||||
} 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 =
|
||||
(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 {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "cmplog.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef USEMMAP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
@ -40,7 +41,7 @@ extern u64 time_spent_working;
|
||||
|
||||
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 *ptr;
|
||||
|
||||
@ -48,10 +49,10 @@ static void at_exit() {
|
||||
if (ptr && *ptr) unlink(ptr);
|
||||
|
||||
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");
|
||||
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
|
||||
if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) kill(pid2, SIGTERM);
|
||||
|
||||
i = 0;
|
||||
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. */
|
||||
@ -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_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_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_ONLY: avoid AFL++'s internal mutators\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_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_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"
|
||||
@ -184,6 +189,7 @@ static void usage(u8 *argv0, int more_help) {
|
||||
" used. Defaults to 200.\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_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_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"
|
||||
@ -350,6 +356,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 's': {
|
||||
|
||||
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
|
||||
rand_set_seed(afl, strtoul(optarg, 0L, 10));
|
||||
afl->fixed_seed = 1;
|
||||
break;
|
||||
@ -419,6 +426,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
case 'i': /* input dir */
|
||||
|
||||
if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
|
||||
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
|
||||
afl->in_dir = optarg;
|
||||
|
||||
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;
|
||||
|
||||
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"); }
|
||||
|
||||
/* 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->skip_deterministic = 0; // force determinsitic fuzzing
|
||||
afl->skip_deterministic = 0; // force deterministic fuzzing
|
||||
afl->old_seed_selection = 1; // force old queue walking seed selection
|
||||
|
||||
if ((c = strchr(afl->sync_id, ':'))) {
|
||||
@ -464,7 +489,24 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
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"); }
|
||||
|
||||
/* 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->is_secondary_node = 1;
|
||||
break;
|
||||
@ -620,6 +662,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
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) {
|
||||
|
||||
FATAL("Multiple -n options not supported");
|
||||
@ -656,7 +704,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
case 'N': /* Unicorn mode */
|
||||
|
||||
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;
|
||||
|
||||
@ -906,7 +954,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
afl->power_name = power_names[afl->schedule];
|
||||
|
||||
if (!afl->sync_id) {
|
||||
if (!afl->non_instrumented_mode && !afl->sync_id) {
|
||||
|
||||
auto_sync = 1;
|
||||
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) {
|
||||
|
||||
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.init_child_func = cmplog_exec_child;
|
||||
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");
|
||||
|
||||
}
|
||||
@ -1436,9 +1505,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
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!");
|
||||
|
||||
}
|
||||
|
||||
show_init_stats(afl);
|
||||
|
||||
if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);
|
||||
|
@ -182,7 +182,7 @@ static void edit_params(int argc, char **argv) {
|
||||
instrim = 1;
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
DEBUGF(
|
||||
"passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
|
||||
"inst_present=%s rt_present=%s rt_lto_present=%s\n",
|
||||
passthrough ? "true" : "false", instrim, gold_pos,
|
||||
@ -280,7 +280,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
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++)
|
||||
SAYF(" \"%s\"", argv[i]);
|
||||
SAYF("\n");
|
||||
@ -315,7 +315,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", thecwd);
|
||||
DEBUGF("cd \"%s\";", thecwd);
|
||||
for (i = 0; i < ld_param_cnt; i++)
|
||||
SAYF(" \"%s\"", ld_params[i]);
|
||||
SAYF("\n");
|
||||
@ -333,7 +333,7 @@ int main(int argc, char **argv) {
|
||||
if (pid < 0) PFATAL("fork() 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) {
|
||||
|
||||
|
@ -667,6 +667,8 @@ static void usage(u8 *argv0) {
|
||||
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
|
||||
"inputs\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_MAP_SIZE: the shared memory size for that target. must be >= the "
|
||||
"size\n"
|
||||
@ -904,7 +906,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST);
|
||||
DEBUGF("");
|
||||
for (i = 0; i < argc; i++)
|
||||
SAYF(" %s", argv[i]);
|
||||
SAYF("\n");
|
||||
@ -1066,7 +1068,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (get_afl_env("AFL_DEBUG")) {
|
||||
|
||||
int i = optind;
|
||||
SAYF(cMGN "[D]" cRST " %s:", fsrv->target_path);
|
||||
DEBUGF("%s:", fsrv->target_path);
|
||||
while (argv[i] != NULL) {
|
||||
|
||||
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,
|
||||
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;
|
||||
|
||||
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
@ -841,17 +842,17 @@ static void usage(u8 *argv0) {
|
||||
"For additional tips, please consult %s/README.md.\n\n"
|
||||
|
||||
"Environment variables used:\n"
|
||||
"TMPDIR: directory to use for temporary input files\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"
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
|
||||
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
|
||||
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
|
||||
" the target was compiled for\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_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);
|
||||
|
||||
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));
|
||||
|
||||
/* initialize cmplog_mode */
|
||||
@ -1141,8 +1159,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
read_initial_file();
|
||||
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
|
||||
afl_fsrv_start(
|
||||
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)
|
||||
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
|
||||
|
@ -5,7 +5,7 @@
|
||||
$ECHO "$BLUE[*] Testing: custom mutator"
|
||||
test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
|
||||
# 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 && {
|
||||
unset AFL_CC
|
||||
# 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
|
||||
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=0x42 -g -fPIC -shared -I../include ../examples/custom_mutators/simple_example.c -o libexamplemutator2.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 ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
|
||||
test -e test-custom-mutator -a -e ./libexamplemutator.so && {
|
||||
# Create input directory
|
||||
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 ; }
|
||||
|
||||
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-mutators
|
||||
} || {
|
||||
|
@ -94,7 +94,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
|
||||
CODE=1
|
||||
}
|
||||
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 && {
|
||||
echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
|
||||
$ECHO "$GREEN[+] gcc_plugin persistent mode feature works correctly"
|
||||
|
@ -57,7 +57,7 @@ test -e ../afl-clang-lto -a -e ../afl-llvm-lto-instrumentation.so && {
|
||||
CODE=1
|
||||
}
|
||||
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 && {
|
||||
echo foo | ../afl-showmap -m none -o /dev/null -q -r ./test-persistent && {
|
||||
$ECHO "$GREEN[+] llvm_mode LTO persistent mode feature works correctly"
|
||||
|
@ -209,7 +209,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
||||
INCOMPLETE=1
|
||||
}
|
||||
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 && {
|
||||
echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
|
||||
$ECHO "$GREEN[+] llvm_mode persistent mode feature works correctly"
|
||||
|
@ -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 && {
|
||||
{
|
||||
# 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
|
||||
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
|
||||
make >>errors 2>&1
|
||||
$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 )" && {
|
||||
$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
|
||||
|
||||
unset AFL_DEBUG_CHILD_OUTPUT
|
||||
unset AFL_DEBUG_CHILD
|
||||
|
||||
}
|
||||
} || {
|
||||
|
@ -1 +1 @@
|
||||
f44ec48f
|
||||
8cca4801
|
||||
|
@ -149,7 +149,7 @@ git status 1>/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[*] initializing unicornafl submodule"
|
||||
git submodule init || exit 1
|
||||
git submodule update 2>/dev/null # ignore errors
|
||||
git submodule update ./unicornafl 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning unicornafl"
|
||||
test -d unicornafl || {
|
||||
|
@ -44,6 +44,7 @@ MAX_SEG_SIZE = 128 * 1024 * 1024
|
||||
# Name of the index file
|
||||
INDEX_FILE_NAME = "_index.json"
|
||||
|
||||
|
||||
#----------------------
|
||||
#---- Helper Functions
|
||||
|
||||
@ -59,14 +60,14 @@ def map_arch():
|
||||
return "arm64be"
|
||||
elif 'armeb' in arch:
|
||||
# check for THUMB mode
|
||||
cpsr = get_register('cpsr')
|
||||
cpsr = get_register('$cpsr')
|
||||
if (cpsr & (1 << 5)):
|
||||
return "armbethumb"
|
||||
else:
|
||||
return "armbe"
|
||||
elif 'arm' in arch:
|
||||
# check for THUMB mode
|
||||
cpsr = get_register('cpsr')
|
||||
cpsr = get_register('$cpsr')
|
||||
if (cpsr & (1 << 5)):
|
||||
return "armlethumb"
|
||||
else:
|
||||
@ -88,12 +89,8 @@ def dump_regs():
|
||||
reg_state = {}
|
||||
for reg in current_arch.all_registers:
|
||||
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
|
||||
|
||||
return reg_state
|
||||
|
||||
|
||||
@ -146,6 +143,21 @@ def dump_process_memory(output_dir):
|
||||
|
||||
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
|
||||
|
||||
@ -173,6 +185,7 @@ def main():
|
||||
context = {
|
||||
"arch": dump_arch_info(),
|
||||
"regs": dump_regs(),
|
||||
"regs_extended": dump_float(),
|
||||
"segments": dump_process_memory(output_path),
|
||||
}
|
||||
|
||||
@ -187,4 +200,3 @@ def main():
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
@ -26,6 +26,13 @@ from unicorn.arm64_const import *
|
||||
from unicorn.x86_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
|
||||
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
|
||||
# Gross but efficient way to find space for the chunk:
|
||||
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:
|
||||
self._uc.mem_map(addr, total_chunk_size, UC_PROT_READ | UC_PROT_WRITE)
|
||||
chunk = self.HeapChunk(addr, total_chunk_size, size)
|
||||
@ -184,29 +191,17 @@ class AflUnicornEngine(Uc):
|
||||
# Load the registers
|
||||
regs = context['regs']
|
||||
reg_map = self.__get_register_map(self._arch_str)
|
||||
for register, value in regs.iteritems():
|
||||
if debug_print:
|
||||
print("Reg {0} = {1}".format(register, value))
|
||||
if not reg_map.has_key(register.lower()):
|
||||
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)))
|
||||
self.__load_registers(regs, reg_map, debug_print)
|
||||
# If we have extra FLOATING POINT regs, load them in!
|
||||
if 'regs_extended' in context:
|
||||
if context['regs_extended']:
|
||||
regs_extended = context['regs_extended']
|
||||
reg_map = self.__get_registers_extended(self._arch_str)
|
||||
self.__load_registers(regs_extended, reg_map, debug_print)
|
||||
|
||||
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)))
|
||||
# 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)
|
||||
if self.__get_arch_and_mode(self.get_arch_str())[0] == UC_ARCH_ARM:
|
||||
self.reg_write(UC_ARM_REG_SP, regs['sp'])
|
||||
|
||||
# Setup the memory map and load memory content
|
||||
self.__map_segments(context['segments'], context_directory, debug_print)
|
||||
@ -253,9 +248,39 @@ class AflUnicornEngine(Uc):
|
||||
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])))
|
||||
|
||||
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
|
||||
"""
|
||||
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:")
|
||||
stack_ptr_addr = self.reg_read(UC_X86_REG_RSP)
|
||||
for i in xrange(-window, window + 1):
|
||||
@ -268,6 +293,31 @@ class AflUnicornEngine(Uc):
|
||||
#-----------------------------
|
||||
#---- 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):
|
||||
# - size is unsigned and must be != 0
|
||||
# - starting address must be aligned to 4KB
|
||||
@ -354,7 +404,7 @@ class AflUnicornEngine(Uc):
|
||||
else:
|
||||
if debug_print:
|
||||
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):
|
||||
arch_map = {
|
||||
@ -398,7 +448,6 @@ class AflUnicornEngine(Uc):
|
||||
"r14": UC_X86_REG_R14,
|
||||
"r15": UC_X86_REG_R15,
|
||||
"rip": UC_X86_REG_RIP,
|
||||
"rsp": UC_X86_REG_RSP,
|
||||
"efl": UC_X86_REG_EFLAGS,
|
||||
"cs": UC_X86_REG_CS,
|
||||
"ds": UC_X86_REG_DS,
|
||||
@ -415,7 +464,6 @@ class AflUnicornEngine(Uc):
|
||||
"esi": UC_X86_REG_ESI,
|
||||
"edi": UC_X86_REG_EDI,
|
||||
"ebp": UC_X86_REG_EBP,
|
||||
"esp": UC_X86_REG_ESP,
|
||||
"eip": UC_X86_REG_EIP,
|
||||
"esp": UC_X86_REG_ESP,
|
||||
"efl": UC_X86_REG_EFLAGS,
|
||||
@ -519,28 +567,96 @@ class AflUnicornEngine(Uc):
|
||||
}
|
||||
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
|
||||
|
||||
# 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
|
||||
"""
|
||||
try:
|
||||
# TODO: Extra mode for Capstone (i.e. Cs(cs_arch, cs_mode + cs_extra) not implemented
|
||||
|
||||
|
||||
def __trace_instruction(self, uc, address, size, user_data):
|
||||
if CAPSTONE_EXISTS == 1:
|
||||
# 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))
|
||||
"""
|
||||
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
|
||||
|
||||
def __trace_instruction(self, uc, address, size, user_data):
|
||||
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):
|
||||
@ -558,3 +674,18 @@ class AflUnicornEngine(Uc):
|
||||
else:
|
||||
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
|
@ -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.
|
||||
|
||||
- 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.
|
||||
|
||||
- socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
|
||||
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
|
||||
graduated to ../instrumentation/*.
|
||||
|
@ -358,8 +358,8 @@ int recv_testcase(int s, void **buf) {
|
||||
|
||||
if ((size & 0xff000000) != 0xff000000) {
|
||||
|
||||
*buf = afl_realloc((void **)&buf, size);
|
||||
if (unlikely(!buf)) { PFATAL("Alloc"); }
|
||||
*buf = afl_realloc(buf, size);
|
||||
if (unlikely(!*buf)) { PFATAL("Alloc"); }
|
||||
received = 0;
|
||||
// fprintf(stderr, "unCOMPRESS (%u)\n", size);
|
||||
while (received < size &&
|
||||
@ -371,8 +371,8 @@ int recv_testcase(int s, void **buf) {
|
||||
#ifdef USE_DEFLATE
|
||||
u32 clen;
|
||||
size -= 0xff000000;
|
||||
*buf = afl_realloc((void **)&buf, size);
|
||||
if (unlikely(!buf)) { PFATAL("Alloc"); }
|
||||
*buf = afl_realloc(buf, size);
|
||||
if (unlikely(!*buf)) { PFATAL("Alloc"); }
|
||||
received = 0;
|
||||
while (received < 4 &&
|
||||
(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"); }
|
||||
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
|
||||
afl_fsrv_start(
|
||||
fsrv, use_argv, &stop_soon,
|
||||
(get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
|
||||
? 1
|
||||
: 0);
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
compressor = libdeflate_alloc_compressor(1);
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer)
|
||||
// Find patch points for untracer tools (e.g. afl++ utils/afl_untracer)
|
||||
//
|
||||
// Copy to ..../Ghidra/Features/Search/ghidra_scripts/
|
||||
// Writes the results to ~/Desktop/patches.txt
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user