Compare commits

...

137 Commits
2.67c ... 2.68c

Author SHA1 Message Date
ee206da389 Merge pull request #545 from AFLplusplus/dev
v2.68c
2020-09-04 22:51:43 +02:00
fac108476c v2.68c 2020-09-04 22:50:45 +02:00
4f7a8a4c70 Merge pull request #542 from AFLplusplus/dev
push to stable
2020-09-04 22:48:46 +02:00
976ee9022c fix assignment 2020-09-04 22:47:37 +02:00
0625eb0a05 avoid signed ints for amounts (which are positive) 2020-09-04 22:26:39 +02:00
77b824d101 compile fix 2020-09-04 17:56:17 +02:00
b7b38205d8 fix travis 2020-09-04 17:37:11 +02:00
6c715f1a69 more changes to fuzzer_setup 2020-09-04 17:04:42 +02:00
fc19aa96f7 Merge pull request #544 from ThomasTNO/export_env_vars
Export set afl_environment_variables to stats
2020-09-04 16:30:15 +02:00
50f61b64b1 Make open_file() inline 2020-09-04 16:22:22 +02:00
809a7cffe2 Write set environment variables in an env file style. 2020-09-04 16:02:09 +02:00
6399f84ba2 fix example 2020-09-04 16:02:02 +02:00
8459bcdf85 fix example 2020-09-04 16:01:08 +02:00
6adaacbb3a Seperate fuzzer_setup from fuzzer_stats, only write fuzzer_setup at the start 2020-09-04 15:54:57 +02:00
6c846bcf2c fix driver test 2020-09-04 15:27:02 +02:00
e45ae8e5da Export set afl_environment_variables to stats 2020-09-04 13:48:43 +02:00
cea2fadbf4 fix afl-whatsup time 2020-09-03 10:27:32 +02:00
4c48d3a3ad update xxh3 to 0.8.0, fix is_ascii 2020-09-03 09:59:23 +02:00
020b8a4964 minor FAQ fixes 2020-09-02 20:19:49 +02:00
08f6e1d66a children terminate on sigpipe 2020-09-02 17:54:54 +02:00
28e457e8d8 add temporary travis target 2020-09-02 10:18:10 +02:00
c7255f2e26 bugfix for Ubuntu trusty: avoid unknown compiler option 2020-09-01 18:55:37 +00:00
6340674a23 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-09-01 19:54:18 +02:00
4538f689ed split-compares-pass: bugfix add missing instrument_file filtering in some places 2020-09-01 19:51:53 +02:00
e4a86b40a5 child cleanup 2020-09-01 13:42:33 +02:00
75c38d6243 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-09-01 12:36:13 +02:00
6f75100602 qemuafl envs 2020-09-01 12:36:04 +02:00
07cee6b750 fix unicorn clean 2020-09-01 11:13:26 +02:00
651ad18e21 added the grammar mutator as a git submodule + documentation 2020-09-01 10:52:39 +02:00
664daa2f3c add qemu driver env var 2020-09-01 01:12:40 +02:00
ed6243df5a Review FAQ.md 2020-09-01 00:49:26 +02:00
bd57784664 code format 2020-08-31 23:59:10 +02:00
7f621509ee Merge pull request #540 from AFLplusplus/dev
Dev
2020-08-31 23:04:09 +02:00
4261e17b3e replace non portable echo -n with printf 2020-08-31 22:08:54 +02:00
8ca4414d70 merge conflicts 2020-08-31 20:34:28 +02:00
6090bb1bca better fix for #539 2020-08-31 20:33:56 +02:00
a552631d3b update changelog 2020-08-31 20:22:20 +02:00
c552229c4d Merge pull request #539 from hazimeh/dev
Fixed stack use-after-return bug in strntoll
2020-08-31 20:20:36 +02:00
2dffed1cff Merge pull request #534 from AFLplusplus/dev
push to stable for GSOC
2020-08-31 19:04:37 +02:00
e93f78eca5 Merge pull request #538 from ploppelop/patch-1
Update parallel_fuzzing.md
2020-08-31 18:44:28 +02:00
9bbbec3fa8 Fixed stack use-after-return bug in strntoll 2020-08-31 18:39:50 +02:00
338638b124 Update parallel_fuzzing.md
fix multisystem example
2020-08-31 18:34:27 +02:00
17e1a72b3b Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-08-31 18:32:33 +02:00
3e6471b949 added files to gitignore 2020-08-31 18:32:28 +02:00
e4de4e3500 update gitignore 2020-08-31 18:32:01 +02:00
bea76b346c fixed build error 2020-08-31 18:29:45 +02:00
53e63e9ded added forkserver init timeout 2020-08-31 18:28:36 +02:00
b1b5e21600 removed dummy 2020-08-31 18:20:39 +02:00
d765740707 hopefully finally fix ancient apple gmake 2020-08-31 18:18:40 +02:00
192cadee34 fix docs 2020-08-31 18:10:18 +02:00
d7d8afa512 fix afl-gcc help output 2020-08-31 17:54:21 +02:00
01fcee1190 fixed make install on mac os 2020-08-31 17:36:16 +02:00
0805437222 fix make man 2020-08-31 17:10:13 +02:00
4398b9b517 fix network server 2020-08-31 16:50:26 +02:00
909262f6c5 fix non portable option -T for 'install' 2020-08-31 16:44:18 +02:00
155ef8875a Fix few warnings for FreeBSD case. (#536) 2020-08-31 16:37:46 +02:00
58cf030546 fix for MacOS sudo 2020-08-31 16:34:57 +02:00
18ea9a8447 omit linker option '--dynamic-list' for MacOS 2020-08-31 16:19:09 +02:00
ebd1e6bc4b Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-08-31 15:40:47 +02:00
45d866d548 typo 2020-08-31 15:40:20 +02:00
8087cf7988 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-08-31 15:17:51 +02:00
9e8b3f13e1 fixed warning on mac 2020-08-31 15:17:37 +02:00
ce4700ca6e Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-08-31 15:17:24 +02:00
8253f90134 typos/wording 2020-08-31 15:16:55 +02:00
86421f3469 Merge pull request #535 from rhertzog/manpages
Fix manpages generated by llvm_mode/GNUMakefile
2020-08-31 15:05:54 +02:00
811ef13b20 Fix manpages generated by llvm_mode/GNUMakefile
* Use a build date derived from SOURCE_DATE_EPOCH like in the main
  Makefile
* Fix the path to the binary
2020-08-31 14:56:02 +02:00
7fb72f1038 typos 2020-08-31 14:47:22 +02:00
d2c9e4baa7 fix warnings and weird code insert 2020-08-31 13:12:59 +02:00
81767287c3 improve documentation 2020-08-31 13:02:40 +02:00
6c980e2a02 rewrite documentation 2020-08-31 12:56:14 +02:00
e7db4d4fe0 fix sync script, update remote sync documentation 2020-08-31 12:36:30 +02:00
567042d146 typos fixed. 2020-08-31 12:32:31 +02:00
4697e4a5a5 description for AFL_MAX_DET_EXTRAS added 2020-08-31 12:26:41 +02:00
92b1f9cf36 added SO link about rand for clarification 2020-08-31 12:11:38 +02:00
bbf00204ea Merge pull request #531 from rhertzog/extend-cflags-safe
Add -fdebug-prefix-map to CFLAGS_SAFE
2020-08-31 11:38:09 +02:00
a42b74b624 Merge pull request #530 from rhertzog/add-cppflags
Pass CPPFLAGS to all calls of the C compiler
2020-08-31 11:33:34 +02:00
7ee255cbcf Merge pull request #529 from rhertzog/manpages
Manual pages related changes
2020-08-31 11:21:52 +02:00
961ddfd7f8 Merge pull request #528 from rhertzog/fix-symlinks
Fix the /usr/bin/afl-clang and afl-clang++ symlinks
2020-08-31 11:19:16 +02:00
4566bcf122 code-format 2020-08-31 10:57:01 +02:00
ca0105ddf6 fix make DEBUG=1 (error seen with gcc 10.2.0) 2020-08-29 21:45:23 +02:00
41bb359428 Fix various spelling errors (#532)
All those spelling errors have been caught by lintian's built-in
spellchecker:
https://lintian.debian.org/tags/spelling-error-in-binary.html
2020-08-28 23:04:25 +02:00
146ede0f29 Add -fdebug-prefix-map to CFLAGS_SAFE
In Debian, we override CFLAGS to include -fdebug-prefix-map to avoid
hardcoding the build path in any generated debug information. This is
to help with getting the package to build reproducibly.

However you seem to voluntarily not honor CFLAGS but only CFLAGS_SAFE
for a limited number of source files. This resulted in a lintian warning
on Debian's side (https://lintian.debian.org/tags/file-references-package-build-path.html)
pointing to /usr/lib/afl/afl-llvm-rt-64.o and /usr/lib/afl/afl-llvm-rt.o.

With this commit, I'm manually adding -fdebug-prefix-map as a safe
build flag to CFLAGS_SAFE.
2020-08-28 22:16:08 +02:00
c0fd7ba6d1 Pass CPPFLAGS to all calls of the C compiler
This variable is a standard way to inject options for the C
preprocessor. It's respected by the implicit rules of make
and autoconf/automake.

Debian sets this variable during package build to inject
`-D_FORTIFY_SOURCE=2` and we would like afl++ to respect it.

Note that this commit also adds $(CFLAGS) in the build of
afl-performance.o where it was missing. It might have been
on purpose but we want to keep CFLAGS everywhere as well
since Debian injects various options through that variable
(for hardening and reproducibility).
2020-08-28 21:55:52 +02:00
b0b2a15891 Improve the generated manual page to be compatible with whatis
And generate the manual page for afl-g++ too.
2020-08-28 21:34:36 +02:00
ff3c9cbd73 Fix installation path of manual pages
Manual pages are stored in /usr/share/man/.
2020-08-28 21:34:08 +02:00
6e839f0f6a Fix the /usr/bin/afl-clang and afl-clang++ symlinks
Right now they are created pointing to '../afl-clang-fast' instead
of 'afl-clang-fast. Given that all the binaries are in the same directory,
the symlinks are effectively broken.
2020-08-28 21:26:32 +02:00
a3cd523250 todo update 2020-08-27 15:24:38 +02:00
b44620f0b0 Merge pull request #526 from h1994st/dev
Prevent afl-fuzz from modifying stage_max during fuzzing
2020-08-27 08:56:08 +02:00
9a6a32775f Prevent afl-fuzz from modifying stage_max during fuzzing 2020-08-27 00:32:53 -04:00
3e8beaafc8 fixing wrong fatal ... 2020-08-26 21:22:24 +02:00
33e58c1d4e some warnings fixes 2020-08-26 14:45:59 +02:00
4be0ea596b rand unlikely added 2020-08-26 13:04:03 +02:00
96ef7083c8 using unbiased rand_below 2020-08-26 05:28:33 +02:00
78eaa6b203 lintokencap: fix compiler complains on Solaris 11. (#525) 2020-08-25 17:11:15 +02:00
1efc6e59b7 Added out_file value when using stdio (#524) 2020-08-24 21:18:51 +02:00
19eddbb0c7 make py functions as optional as they are in the doc 2020-08-24 18:12:08 +02:00
6a34c5aa3e fix python implementation for new function 2020-08-24 18:06:07 +02:00
c7f0d30668 added afl_custom_fuzz_count 2020-08-24 17:32:41 +02:00
a7c3f252d5 unicorn build warning for MUSL based linux distros. (#510) 2020-08-24 12:06:04 +02:00
b9b6f06429 Allow Large Extras (#523)
* allow large extras

* skipping large testcases again
2020-08-24 12:04:29 +02:00
a1442bd1ac no longer warns for prob. extras 2020-08-23 11:21:49 +02:00
4d9d52e3d9 code format 2020-08-23 11:00:46 +02:00
6184832ea9 added more env var docs, fsrv fixes for cmin, tmin 2020-08-23 10:59:56 +02:00
e2b54bfa05 code format 2020-08-23 10:40:46 +02:00
425908a00c Option for specifying forkserver initialization timeout via environment variable (#522)
* Addition of AFL_FORKSRV_INIT_TMOUT env var

This commit introduces a new environment variable which allows to
specify the timespan AFL should wait for initial contact with the
forkserver.

This is useful for fuzz-targets requiring a rather long setup time
before the actual fuzzing can be started (e.g., unicorn).

* add .swp files to .gitignore

* Inherit init_tmout in afl_fsrv_init_dup

Without this patch, the forkserver would spawn with a timeout of 0 in
cmplog mode, leading to an immediate crash.

Additionally, this commit removes a spurious whitespace.

* Initialize afl->fsrv.init_tmout in afl_fsrv_init

Not all afl-components will need the new AFL_FORKSRV_INIT_TMOUT
environment variable. Hence, it's initialized to the safe "default"
value from before in afl_fsrv_init now.
2020-08-23 10:39:34 +02:00
1301552101 added AFL_MAX_DET_EXTRAS env var 2020-08-23 01:48:36 +02:00
c4f71ab201 enable autodict for cmplog compile, it is ensure not be used in the forkserver 2020-08-22 10:01:45 +02:00
42ef1968a5 Merge pull request #521 from AFLplusplus/dev
Push to stable to fix wrong free on exit
2020-08-22 01:30:21 +02:00
5ec91fce23 fix for bad free (#520) 2020-08-21 23:03:08 +02:00
47878f6974 add execs_done to plot file 2020-08-21 23:33:35 +02:00
d5c77a9e96 update todo 2020-08-21 15:45:15 +02:00
4d2694c114 fix semicolon 2020-08-21 15:26:43 +02:00
017c8a6940 fix global id documentation for LTO pcguard 2020-08-21 14:39:47 +02:00
b0a783e86f code format 2020-08-21 11:18:18 +02:00
714e4d2b46 fixed for LTO llvm 11 2020-08-21 11:17:03 +02:00
85a4c5e724 only compile SanitizerCoverage for LTO 2020-08-21 10:50:06 +02:00
182b8b3e14 remove doc reference for SKIPSINGLEBLOCK 2020-08-20 19:00:15 +02:00
4ce5ed370a LTO: sancov made default, deprecated SKIPSINGLEBLOCK, deactivate LTO autodict for cmplog binaries 2020-08-20 18:57:05 +02:00
f7bac482e9 Merge pull request #518 from AFLplusplus/ltopcguard
sancov ported to LTO
2020-08-20 18:33:53 +02:00
bd074e9150 add missing features for sancov lto 2020-08-20 18:32:22 +02:00
d52ea44c27 fix wrong var 2020-08-20 18:27:22 +02:00
9c1b6cfb99 Merge pull request #517 from AFLplusplus/custommut-readme
Custom Mutator readme
2020-08-20 14:21:42 +02:00
631d3f274a move afl_loop check 2020-08-20 13:49:11 +02:00
3cdaf4dcf2 sancov enhancement 2020-08-20 13:37:34 +02:00
572944d726 Merge pull request #514 from AFLplusplus/dev
push to stable
2020-08-20 11:00:07 +02:00
779d8f6b7e support current llvm12 changes 2020-08-20 10:56:51 +02:00
322847755a Merge pull request #513 from fouzhe/patch-1
fix typo
2020-08-19 17:58:35 +02:00
f9f28b9c7c fix typo 2020-08-19 23:54:45 +08:00
c3bc0145e7 Merge pull request #512 from AFLplusplus/stable
activate travis for stable
2020-08-19 16:21:03 +02:00
17d403b8f8 activate travis for stable 2020-08-19 16:19:31 +02:00
9faf7b6fc8 v2.67d 2020-08-18 20:08:29 +02:00
5c759953f4 Merge pull request #511 from AFLplusplus/stable
push to dev
2020-08-18 20:05:56 +02:00
b504b9313a code-format, changelog 2020-08-18 01:36:49 +02:00
1a94cfe2af moved autodict extras away from extras_a 2020-08-18 01:31:40 +02:00
7470b475a9 Reworked maybe_grow to take a single ptr, renamed to afl_realloc (#505)
* maybe_grow takes a single ptr

* fixed use_deflate

* reworked maybe_grow_bufsize

* helper to access underlying buf

* remove redundant realloc_block

* code format

* fixes

* added unit tests

* renamed maybe_grow to afl_realloc

* BUF_PARAMS -> AFL_BUF_PARAM
2020-08-18 00:50:52 +02:00
f92607cff1 pcguard for lto 2020-08-17 22:56:48 +02:00
6b1ad311da Custom Mutator readme 2020-08-07 14:20:38 +02:00
66 changed files with 6281 additions and 5203 deletions

4
.gitignore vendored
View File

@ -1,8 +1,10 @@
.test
.test2
.sync_tmp
.vscode
*.o
*.so
*.swp
*.pyc
*.dSYM
as
@ -10,6 +12,7 @@ ld
in
out
core*
compile_commands.json
afl-analyze
afl-as
afl-clang
@ -39,6 +42,7 @@ afl-cmin.8
afl-cmin.bash.8
afl-fuzz.8
afl-gcc.8
afl-g++.8
afl-gcc-fast.8
afl-g++-fast.8
afl-gotcpu.8

6
.gitmodules vendored
View File

@ -1,3 +1,7 @@
[submodule "unicorn_mode/unicornafl"]
path = unicorn_mode/unicornafl
url = https://github.com/AFLplusplus/unicornafl.git
url = https://github.com/AFLplusplus/unicornafl
[submodule "custom_mutators/Grammar-Mutator"]
path = custom_mutators/Grammar-Mutator
url = https://github.com/AFLplusplus/Grammar-Mutator

View File

@ -4,8 +4,9 @@ sudo: required
branches:
only:
- master
- stable
- dev
- llvm_merge
matrix:
include:

View File

@ -24,31 +24,30 @@ BIN_PATH = $(PREFIX)/bin
HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH = $(PREFIX)/share/doc/afl
MISC_PATH = $(PREFIX)/share/afl
MAN_PATH = $(PREFIX)/man/man8
MAN_PATH = $(PREFIX)/share/man/man8
PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
# PROGS intentionally omit afl-as, which gets installed elsewhere.
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
PROGS = afl-gcc afl-g++ afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
ASAN_OPTIONS=detect_leaks=0
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=full
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto
endif
endif
endif
endif
endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
@ -62,7 +61,10 @@ ifneq "$(shell uname)" "Darwin"
endif
endif
# OS X does not like _FORTIFY_SOURCE=2
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
# _FORTIFY_SOURCE=2 does not like -O0
ifndef DEBUG
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
endif
endif
ifeq "$(shell uname)" "SunOS"
@ -204,7 +206,10 @@ else
endif
ifneq "$(filter Linux GNU%,$(shell uname))" ""
# _FORTIFY_SOURCE=2 does not like -O0
ifndef DEBUG
override CFLAGS += -D_FORTIFY_SOURCE=2
endif
LDFLAGS += -ldl -lrt
endif
@ -274,7 +279,7 @@ endif
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
man: $(MANPAGES)
man: afl-gcc all $(MANPAGES)
tests: source-only
@cd test ; ./test-all.sh
@ -367,79 +372,81 @@ endif
ready:
@echo "[+] Everything seems to be working, ready to compile."
afl-g++: afl-gcc
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS)
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS)
ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
$(CC) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
$(CC) $(CFLAGS) $(CPPFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-common.c -o src/afl-common.o
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-forkserver.c -o src/afl-forkserver.o
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -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) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS)
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
# document all mutations and only do one run (use with only one input file!)
document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_maybe_alloc
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
unit_hash: test/unittests/unit_hash.o src/afl-performance.o
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_hash
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_rand
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
unit_list: test/unittests/unit_list.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_list
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
unit_preallocable: test/unittests/unit_preallocable.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_preallocable
unit_clean:
@ -486,7 +493,7 @@ ifndef AFL_NO_X86
test_build: afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper and instrumentation output..."
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_AS_FORCE_INSTRUMENT=1 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; 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
@ -523,7 +530,7 @@ clean:
$(MAKE) -C qemu_mode/libcompcov clean
rm -rf qemu_mode/qemu-3.1.1
ifeq "$(IN_REPO)" "1"
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
else
rm -rf qemu_mode/qemu-3.1.1.tar.xz
rm -rf unicorn_mode/unicornafl
@ -566,7 +573,8 @@ source-only: all
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@echo .SH NAME >> $@
@echo .B $* >> $@
@printf "%s" ".B $* \- " >> $@
@./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> $@
@echo >> $@
@echo .SH SYNOPSIS >> $@
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@

View File

@ -4,9 +4,9 @@
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=stable)
Release Version: [2.67c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release Version: [2.68c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 2.67d
Github Version: 3.00a
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -19,7 +19,7 @@
Originally developed by Michał "lcamtuf" Zalewski.
afl++ is a superiour fork to Google's afl - more speed, more and better
afl++ is a superior fork to Google's afl - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
## Contents
@ -75,7 +75,7 @@
* C. Holler's afl-fuzz Python mutator module: [https://github.com/choller/afl](https://github.com/choller/afl)
* Custom mutator by a library (instead of Python) by kyakdan
* LAF-Intel/CompCov support for llvm_mode, qemu_mode and unicorn_mode (with enhanced capabilities)
* Radamsa and hongfuzz mutators (as custom mutators).
* Radamsa and honggfuzz mutators (as custom mutators).
* QBDI mode to fuzz android native libraries via Quarkslab's [QBDI](https://github.com/QBDI/QBDI) framework
* Frida and ptrace mode to fuzz binary-only libraries, etc.
@ -95,7 +95,7 @@
The following branches exist:
* [stable/trunk](https://github.com/AFLplusplus/AFLplusplus/) : stable state of afl++ - it is synced from dev from time to
time when we are satisfied with it's stability
time when we are satisfied with its stability
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
checkout which does not compile or has a bug. *We only accept PRs in dev!!*
* (any other) : experimental branches to work on specific features or testing
@ -210,7 +210,7 @@ If you find other good ones, please send them to us :-)
The following describes how to fuzz with a target if source code is available.
If you have a binary-only target please skip to [#Instrumenting binary-only apps](#Instrumenting binary-only apps)
Fuzzing source code is a three step process.
Fuzzing source code is a three-step process.
1. compile the target with a special compiler that prepares the target to be
fuzzed efficiently. This step is called "instrumenting a target".
@ -318,7 +318,7 @@ here:
#### c) Modify the target
If the target has features that makes fuzzing more difficult, e.g.
If the target has features that make fuzzing more difficult, e.g.
checksums, HMAC, etc. then modify the source code so that this is
removed.
This can even be done for productional source code be eliminating
@ -579,7 +579,7 @@ It is even better to check out the exact lines of code that have been reached -
and which have not been found so far.
An "easy" helper script for this is [https://github.com/vanhauser-thc/afl-cov](https://github.com/vanhauser-thc/afl-cov),
just follow the README of that seperate project.
just follow the README of that separate project.
If you see that an important area or a feature has not been covered so far then
try to find an input that is able to reach that and start a new secondary in
@ -661,7 +661,7 @@ on-the-fly instrumentation of black-box binaries.
### QEMU
For linux programs and it's libraries this is accomplished with a version of
For linux programs and its libraries this is accomplished with a version of
QEMU running in the lesser-known "user space emulation" mode.
QEMU is a project separate from AFL, but you can conveniently build the
feature by doing:
@ -684,7 +684,7 @@ For non-Linux binaries you can use afl++'s unicorn mode which can emulate
anything you want - for the price of speed and the user writing scripts.
See [unicorn_mode](unicorn_mode/README.md).
It can be easily build by:
It can be easily built by:
```shell
cd unicorn_mode
./build_unicorn_support.sh
@ -1035,6 +1035,7 @@ without feedback, bug reports, or patches from:
Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu
Josephine Calliotte Konrad Welc
Thomas Rooijakkers
```
Thank you!

12
TODO.md
View File

@ -1,10 +1,12 @@
# TODO list for AFL++
## Roadmap 2.67+
## Roadmap 2.68+
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- CPU affinity for many cores? There seems to be an issue > 96 cores
- afl-plot to support multiple plot_data
- afl_custom_fuzz_splice_optin()
- intel-pt tracer
## Further down the road
@ -13,16 +15,12 @@ afl-fuzz:
- add __sanitizer_cov_trace_cmp* support via shmem
llvm_mode:
- LTO - imitate sancov
- add __sanitizer_cov_trace_cmp* support
gcc_plugin:
- (wait for submission then decide)
- laf-intel
- better instrumentation (seems to be better with gcc-9+)
qemu_mode:
- update to 5.x (if the performance bug is gone)
- non colliding instrumentation
- rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END,
AFL_COMPCOV_LEVEL?)
@ -36,9 +34,9 @@ qemu_mode:
- LTO/sancov: write current edge to prev_loc and use that information when
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow
up edge numbers that both following cmp paths have been found and then
disable working on this edge id
disable working on this edge id -> cmplog_intelligence branch
- new tancov: use some lightweight taint analysis to see which parts of a
new queue entry is accessed and only fuzz these bytes - or better, only
fuzz those bytes that are newly in coverage compared to the queue entry
the new one is based on
the new one is based on -> taint branch, not useful :-(

View File

@ -120,6 +120,7 @@ function usage() {
"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"
exit 1
}

View File

@ -99,7 +99,7 @@ fi
fmt_duration()
{
DUR_STRING=
if [ $1 -eq 0 ]; then
if [ $1 -le 0 ]; then
return 1
fi
@ -109,7 +109,11 @@ fmt_duration()
local minutes=$(((duration / 60) % 60))
local seconds=$((duration % 60))
if [ $days -gt 0 ]; then
if [ $duration -le 0 ]; then
DUR_STRING="0 seconds"
elif [ $duration -eq 1 ]; then
DUR_STRING="1 second"
elif [ $days -gt 0 ]; then
DUR_STRING="$days days, $hours hours"
elif [ $hours -gt 0 ]; then
DUR_STRING="$hours hours, $minutes minutes"

View File

@ -3,6 +3,22 @@
Custom mutators enhance and alter the mutation strategies of afl++.
For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
## The afl++ Grammar Mutator
If you use git to clone afl++, then the following will incorporate our
excellent grammar custom mutator:
```
git submodule init
git submodule update
```
otherwise just checkout the repository here with either
`git clone https://github.com/AFLplusplus/Grammar-Mutator` or
`svn co https://github.com/AFLplusplus/Grammar-Mutator`.
Read the [Grammar-Mutator/README.md](Grammar-Mutator/README.md) on how to use
it.
## Production-Ready Custom Mutators
This directory holds ready to use custom mutators.

View File

@ -15,14 +15,14 @@ libradamsa.a: libradamsa.c radamsa.h
@echo " ***************************************************************"
@echo " * Compiling libradamsa, wait some minutes (~3 on modern CPUs) *"
@echo " ***************************************************************"
$(CC) -fPIC $(CFLAGS) -I $(CUR_DIR) -o libradamsa.a -c libradamsa.c
$(CC) -fPIC $(CFLAGS) $(CPPFLAGS) -I $(CUR_DIR) -o libradamsa.a -c libradamsa.c
radamsa-mutator.so: radamsa-mutator.c libradamsa.a
$(CC) $(CFLAGS) -g -I. -I../../include -shared -fPIC -c radamsa-mutator.c
$(CC) $(CFLAGS) -shared -fPIC -o radamsa-mutator.so radamsa-mutator.o libradamsa.a
$(CC) $(CFLAGS) $(CPPFLAGS) -g -I. -I../../include -shared -fPIC -c radamsa-mutator.c
$(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC -o radamsa-mutator.so radamsa-mutator.o libradamsa.a
test: libradamsa.a libradamsa-test.c
$(CC) $(CFLAGS) -I $(CUR_DIR) -o libradamsa-test libradamsa-test.c libradamsa.a
$(CC) $(CFLAGS) $(CPPFLAGS) -I $(CUR_DIR) -o libradamsa-test libradamsa-test.c libradamsa.a
./libradamsa-test libradamsa-test.c | grep "library test passed"
rm /tmp/libradamsa-*.fuzz

View File

@ -324,7 +324,7 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
}
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
void * scratch_buf = *buf1;

View File

@ -9,6 +9,34 @@ Want to stay in the loop on major new features? Join our mailing list by
sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++2.68c (release)
- added the GSoC excellent afl++ grammar mutator by Shengtuo to our
custom_mutators/ (see custom_mutators/README.md) - or get it here:
https://github.com/AFLplusplus/Grammar-Mutator
- a few QOL changes for Apple and its outdated gmake
- afl-fuzz:
- fix for auto dictionary entries found during fuzzing to not throw out
a -x dictionary
- added total execs done to plot file
- AFL_MAX_DET_EXTRAS env variable added to control the amount of
deterministic dict entries without recompiling.
- AFL_FORKSRV_INIT_TMOUT env variable added to control the time to wait
for the forkserver to come up without the need to increase the overall
timeout.
- bugfix for cmplog that results in a heap overflow based on target data
(thanks to the magma team for reporting!)
- write fuzzing setup into out/fuzzer_setup (environment variables and
command line)
- custom mutators:
- added afl_custom_fuzz_count/fuzz_count function to allow specifying
the number of fuzz attempts for custom_fuzz
- llvm_mode:
- ported SanCov to LTO, and made it the default for LTO. better
instrumentation locations
- Further llvm 12 support (fast moving target like afl++ :-) )
- deprecated LLVM SKIPSINGLEBLOCK env environment
### Version ++2.67c (release)
- Support for improved afl++ snapshot module:
https://github.com/AFLplusplus/AFL-Snapshot-LKM
@ -22,6 +50,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- expanded havoc mode added, on no cycle finds add extra splicing and
MOpt into the mix
- fixed a bug in redqueen for strings and made deterministic with -s
- Compiletime autodictionary fixes
- llvm_mode:
- now supports llvm 12
- support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous
@ -396,7 +425,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- big code refactoring:
* all includes are now in include/
* all afl sources are now in src/ - see src/README.md
* afl-fuzz was splitted up in various individual files for including
* afl-fuzz was split up in various individual files for including
functionality in other programs (e.g. forkserver, memory map, etc.)
for better readability.
* new code indention everywhere

View File

@ -4,11 +4,11 @@
* [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl)
* [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
* [How do I fuzz a network service?](#how-to-fuzz-a-network-service)
* [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program)
* [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service)
* [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program)
* [What is an edge?](#what-is-an-edge)
* [Why is my stability below 100%?](#why-is-my-stability-below-100)
* [How can I improve the stability value](#how-can-i-improve-the-stability-value)
* [How can I improve the stability value?](#how-can-i-improve-the-stability-value)
If you find an interesting or important question missing, submit it via
[https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues)
@ -18,51 +18,52 @@ If you find an interesting or important question missing, submit it via
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting in
2013/2014, and when he left Google end of 2017 he stopped developing it.
At the end of 2019 the Google fuzzing team took over maintance of AFL, however
it is only accepting PR from the community and is not developing enhancements
At the end of 2019 the Google fuzzing team took over maintenance of AFL, however
it is only accepting PRs from the community and is not developing enhancements
anymore.
In the second quarter of 2019, 1 1/2 years after no further development of
AFL had happened and it became clear there would be none coming, afl++
was born, where initially first community patches were collected and applied
for bugs and enhancements. Then from various AFL spin-offs - mostly academic
In the second quarter of 2019, 1 1/2 year later when no further development of
AFL had happened and it became clear there would none be coming, afl++
was born, where initially community patches were collected and applied
for bug fixes and enhancements. Then from various AFL spin-offs - mostly academic
research - features were integrated. This already resulted in a much advanced
AFL.
Until the end of 2019 the afl++ team had grown to four active developers which
then implemented their own research and feature, making it now by far the most
then implemented their own research and features, making it now by far the most
flexible and feature rich guided fuzzer available as open source.
And in independent fuzzing benchmarks it is one of the best fuzzers available,
e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html)
## How to improve the fuzzing speed
## How to improve the fuzzing speed?
1. use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
2. Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase)
3. Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase)
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
5. Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure)
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
5. Improve Linux kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system less secure)
6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem
7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads)
## How do I fuzz a network service?
The short answer is - you cannot, at least "out of the box".
The short answer is - you cannot, at least not "out of the box".
Using network has a slow-down of x10-20 on the fuzzing speed, does not scale,
and finally usually it is more than one initial data packet but a back-and-forth
which is totally unsupported by most coverage aware fuzzers.
Using a network channel is inadequate for several reasons:
- it has a slow-down of x10-20 on the fuzzing speed
- it does not scale to fuzzing multiple instances easily,
- instead of one initial data packet often a back-and-forth interplay of packets is needed for stateful protocols (which is totally unsupported by most coverage aware fuzzers).
The established method to fuzz network services is to modify the source code
to read from a file or stdin (fd 0) (or even faster via shared memory, combine
this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md)
and you have a performance gain of x10 instead of a performance loss of over
x10 - that is a x100 difference!
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 network would be.
See [examples/socket_fuzzing/](../examples/socket_fuzzing/)
to emulate the network. This is also much faster than the real network would be.
See [examples/socket_fuzzing/](../examples/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) -
@ -73,7 +74,7 @@ which allows you to define network state with different type of data packets.
If the GUI program can read the fuzz data from a file (via the command line,
a fixed location or via an environment variable) without needing any user
interaction then then yes.
interaction then it would be suitable for fuzzing.
Otherwise it is not possible without modifying the source code - which is a
very good idea anyway as the GUI functionality is a huge CPU/time overhead
@ -82,13 +83,13 @@ for the fuzzing.
So create a new `main()` that just reads the test case and calls the
functionality for processing the input that the GUI program is using.
## What is an "edge"
## What is an "edge"?
A program contains `functions`, `functions` contain the compiled machine code.
The compiled machine code in a `function` can be in a single or many `basic blocks`.
A `basic block` is the largest possible number of subsequent machine code
instructions that runs independent, meaning it does not split up to different
locations nor is it jumped into it from a different location:
instructions that has exactly one entrypoint (which can be be entered by multiple other basic blocks)
and runs linearly without branching or jumping to other addresses (except at the end).
```
function() {
A:
@ -98,7 +99,7 @@ function() {
if (x) goto C; else goto D;
C:
some code
goto D
goto E
D:
some code
goto B
@ -108,7 +109,7 @@ function() {
```
Every code block between two jump locations is a `basic block`.
An `edge` is then the unique relationship between two `basic blocks` (from the
An `edge` is then the unique relationship between two directly connected `basic blocks` (from the
code example above):
```
Block A
@ -123,8 +124,9 @@ code example above):
Block E
```
Every line between two blocks is an `edge`.
Note that a few basic block loop to itself, this too would be an edge.
## Why is my stability below 100%
## Why is my stability below 100%?
Stability is measured by how many percent of the edges in the target are
"stable". Sending the same input again and again should take the exact same
@ -132,37 +134,37 @@ path through the target every time. If that is the case, the stability is 100%.
If however randomness happens, e.g. a thread reading other external data,
reaction to timing, etc. then in some of the re-executions with the same data
the result in the edge information will be different accross runs.
the edge coverage result will be different accross runs.
Those edges that change are then flagged "unstable".
The more "unstable" edges, the more difficult for afl++ to identify valid new
paths.
A value above 90% is usually fine and a value above 80% is also still ok, and
even above 20% can still result in successful finds of bugs.
However, it is recommended that below 90% or 80% you should take measures to
improve the stability.
even a value above 20% can still result in successful finds of bugs.
However, it is recommended that for values below 90% or 80% you should take
countermeasures to improve stability.
## How can I improve the stability value
## How can I improve the stability value?
For fuzzing a 100% stable target that covers all edges is the best.
For fuzzing a 100% stable target that covers all edges is the best case.
A 90% stable target that covers all edges is however better than a 100% stable
target that ignores 10% of the edges.
With instability you basically have a partial coverage loss on an edge, with
ignore you have a full loss on that edge.
ignored functions you have a full loss on that edges.
There are functions that are unstable, but also provide value to coverage, eg
init functions that use fuzz data as input for example.
If however it is a function that has nothing to do with the input data is the
source, e.g. checking jitter, or is a hash map function etc. then it should
not be instrumented.
If however a function that has nothing to do with the input data is the
source of instability, e.g. checking jitter, or is a hash map function etc.
then it should not be instrumented.
To be able to make this decision the following process will allow you to
identify the functions with variable edges so you can make this decision.
To be able to exclude these functions (based on AFL++'s measured stability)
the following process will allow to identify functions with variable edges.
Four steps are required to do this and requires quite some knowledge of
coding and/or disassembly and it is only effectively possible with
Four steps are required to do this and it also requires quite some knowledge
of coding and/or disassembly and is effectively possible only with
afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
1. First step: Identify which edge ID numbers are unstable
@ -171,7 +173,7 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
The out/fuzzer_stats file will then show the edge IDs that were identified
as unstable.
2. Second step: Find the responsible function.
2. Second step: Find the responsible function(s).
a) For LTO instrumented binaries this can be documented during compile
time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`.
@ -191,20 +193,20 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation.
and set a write breakpoint to that address (`watch 0x.....`).
c) in all other instrumentation types this is not possible. So just
recompile with the the two mentioned above. This is just for
recompile with the two mentioned above. This is just for
identifying the functions that have unstable edges.
3. Third step: create a text file with the filenames/functions
Identify which source code files contain the functions that you need to
remove from instrumentation, or just specify the functions you want to
skip instrumenting. Note that optimization might inline functions!
skip for instrumentation. Note that optimization might inline functions!
Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md)
If PCGUARD is used, then you need to follow this guide (needs llvm 12+!):
[http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
Only deny those functions from instrumentation that provide no value
Only exclude those functions from instrumentation that provide no value
for coverage - that is if it does not process any fuzz data directly
or indirectly (e.g. hash maps, thread management etc.).
If however a function directly or indirectly handles fuzz data then you

View File

@ -6,14 +6,14 @@
However, if there is only the binary program and no source code available,
then standard `afl-fuzz -n` (non-instrumented mode) is not effective.
The following is a description of how these binaries can be fuzzed with afl++
The following is a description of how these binaries can be fuzzed with afl++.
## TL;DR:
qemu_mode in persistent mode is the fastest - if the stability is
high enough. Otherwise try retrowrite, afl-dyninst and if these
fail too then standard qemu_mode with AFL_ENTRYPOINT to where you need it.
fail too then try standard qemu_mode with AFL_ENTRYPOINT to where you need it.
If your target is a library use examples/afl_frida/.
@ -29,10 +29,10 @@
The speed decrease is at about 50%.
However various options exist to increase the speed:
- using AFL_ENTRYPOINT to move the forkserver to a later basic block in
- using AFL_ENTRYPOINT to move the forkserver entry to a later basic block in
the binary (+5-10% speed)
- using persistent mode [qemu_mode/README.persistent.md](../qemu_mode/README.persistent.md)
this will result in 150-300% overall speed - so 3-8x the original
this will result in 150-300% overall speed increase - so 3-8x the original
qemu_mode speed!
- using AFL_CODE_START/AFL_CODE_END to only instrument specific parts
@ -104,7 +104,7 @@
## RETROWRITE
If you have an x86/x86_64 binary that still has it's symbols, is compiled
If you have an x86/x86_64 binary that still has its symbols, is compiled
with position independant code (PIC/PIE) and does not use most of the C++
features then the retrowrite solution might be for you.
It decompiles to ASM files which can then be instrumented with afl-gcc.
@ -148,7 +148,7 @@
## CORESIGHT
Coresight is ARM's answer to Intel's PT.
There is no implementation so far which handle coresight and getting
There is no implementation so far which handles coresight and getting
it working on an ARM Linux is very difficult due to custom kernel building
on embedded systems is difficult. And finding one that has coresight in
the ARM chip is difficult too.

View File

@ -32,6 +32,7 @@ performed with the custom mutator.
C/C++:
```c
void *afl_custom_init(afl_t *afl, unsigned int seed);
uint32_t afl_custom_fuzz_count(void *data, const u8 *buf, size_t buf_size);
size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size);
size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf);
int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size);
@ -49,6 +50,9 @@ Python:
def init(seed):
pass
def fuzz_count(buf, add_buf, max_size):
return cnt
def fuzz(buf, add_buf, max_size):
return mutated_out
@ -88,6 +92,14 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
This method determines whether the custom fuzzer should fuzz the current
queue entry or not
- `fuzz_count` (optional):
When a queue entry is selected to be fuzzed, afl-fuzz selects the number
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.
- `fuzz` (optional):
This method performs custom mutations on a given input. It also accepts an

View File

@ -10,8 +10,8 @@
Because they can't directly accept command-line options, the compile-time
tools make fairly broad use of environmental variables:
- Most afl tools do not print any ouput if stout/stderr are redirected.
If you want to have the output into a file then set the AFL_DEBUG
- Most afl tools do not print any output if stdout/stderr are redirected.
If you want to save the output in a file then set the AFL_DEBUG
environment variable.
This is sadly necessary for various build processes which fail otherwise.
@ -44,7 +44,7 @@ tools make fairly broad use of environmental variables:
you instrument hand-written assembly when compiling clang code by plugging
a normalizer into the chain. (There is no equivalent feature for GCC.)
- Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the
- Setting AFL_INST_RATIO to a percentage between 0% and 100% controls the
probability of instrumenting every branch. This is (very rarely) useful
when dealing with exceptionally complex programs that saturate the output
bitmap. Examples include v8, ffmpeg, and perl.
@ -83,17 +83,12 @@ tools make fairly broad use of environmental variables:
The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset
of the settings discussed in section #1, with the exception of:
- Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting
functions with a single basic block. This is useful for most C and
some C++ targets. This works for all instrumentation modes.
- AFL_AS, since this toolchain does not directly invoke GNU as.
- TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are
created.
- AFL_INST_RATIO, as we switched for instrim instrumentation which
is more effective but makes not much sense together with this option.
- AFL_INST_RATIO, as we by default use collision free instrumentation.
Then there are a few specific features that are only available in llvm_mode:
@ -121,11 +116,12 @@ Then there are a few specific features that are only available in llvm_mode:
built if LLVM 11 or newer is used.
- AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
(not recommended!)
(not recommended for afl-clang-fast, default for afl-clang-lto as there
it is a different and better kind of instrumentation.)
None of the following options are necessary to be used and are rather for
manual use (which only ever the author of this LTO implementation will use).
These are used if several seperated instrumentation are performed which
These are used if several seperated instrumentations are performed which
are then later combined.
- AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given
@ -204,7 +200,7 @@ Then there are a few specific features that are only available in llvm_mode:
### INSTRUMENT LIST (selectively instrument files and functions)
This feature allows selectively instrumentation of the source
This feature allows selective instrumentation of the source
- Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or
function will only instrument (or skip) those files that match the names
@ -282,6 +278,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 yout 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 `1000` milis. 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.
@ -373,6 +377,16 @@ checks or alter some of the more exotic semantics of the tool:
Note that this setting inhibits some of the user-friendly diagnostics
normally done when starting up the forkserver and causes a pretty
significant performance drop.
- Setting AFL_MAX_DET_EXTRAS changes the count of dictionary entries/extras
(default 200), after which the entries will be used probabilistically.
So, if the dict/extras file (`-x`) contains more tokens than this threshold,
not all of the tokens will be used in each fuzzing step, every time.
Instead, there is a chance that the entry will be skipped during fuzzing.
This makes sure that the fuzzer doesn't spend all its time only inserting
the extras, but will still do other mutations. However, it decreases the
likelihood for each token to be inserted, before the next queue entry is fuzzed.
Either way, all tokens will be used eventually, in a longer fuzzing campaign.
- Outdated environment variables that are that not supported anymore:
AFL_DEFER_FORKSRV

View File

@ -10,8 +10,8 @@ n-core system, you can almost always run around n concurrent fuzzing jobs with
virtually no performance hit (you can use the afl-gotcpu tool to make sure).
In fact, if you rely on just a single job on a multi-core system, you will
be underutilizing the hardware. So, parallelization is usually the right
way to go.
be underutilizing the hardware. So, parallelization is always the right way to
go.
When targeting multiple unrelated binaries or using the tool in
"non-instrumented" (-n) mode, it is perfectly fine to just start up several
@ -65,22 +65,7 @@ still perform deterministic checks; while the secondary instances will
proceed straight to random tweaks.
Note that you must always have one -M main instance!
Note that running multiple -M instances is wasteful, although there is an
experimental support for parallelizing the deterministic checks. To leverage
that, you need to create -M instances like so:
```
./afl-fuzz -i testcase_dir -o sync_dir -M mainA:1/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M mainB:2/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M mainC:3/3 [...]
```
...where the first value after ':' is the sequential ID of a particular main
instance (starting at 1), and the second value is the total number of fuzzers to
distribute the deterministic fuzzing across. Note that if you boot up fewer
fuzzers than indicated by the second number passed to -M, you may end up with
poor coverage.
Running multiple -M instances is wasteful!
You can also monitor the progress of your jobs from the command line with the
provided afl-whatsup tool. When the instances are no longer finding new paths,
@ -99,61 +84,88 @@ example may be:
This is not a concern if you use @@ without -f and let afl-fuzz come up with the
file name.
## 3) Syncing with non-afl fuzzers or independant instances
## 3) Multiple -M mains
There is support for parallelizing the deterministic checks.
This is only needed where
1. many new paths are found fast over a long time and it looks unlikely that
main node will ever catch up, and
2. deterministic fuzzing is actively helping path discovery (you can see this
in the main node for the first for lines in the "fuzzing strategy yields"
section. If the ration `found/attemps` is high, then it is effective. It
most commonly isn't.)
Only if both are true it is beneficial to have more than one main.
You can leverage this by creating -M instances like so:
```
./afl-fuzz -i testcase_dir -o sync_dir -M mainA:1/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M mainB:2/3 [...]
./afl-fuzz -i testcase_dir -o sync_dir -M mainC:3/3 [...]
```
... where the first value after ':' is the sequential ID of a particular main
instance (starting at 1), and the second value is the total number of fuzzers to
distribute the deterministic fuzzing across. Note that if you boot up fewer
fuzzers than indicated by the second number passed to -M, you may end up with
poor coverage.
## 4) Syncing with non-afl fuzzers or independant instances
A -M main node can be told with the `-F other_fuzzer_queue_directory` option
to sync results from other fuzzers, e.g. libfuzzer or honggfuzz.
Only the specified directory will by synced into afl, not subdirectories.
The specified directories do not need to exist yet at the start of afl.
The specified directory does not need to exist yet at the start of afl.
## 4) Multi-system parallelization
The `-F` option can be passed to the main node several times.
## 5) Multi-system parallelization
The basic operating principle for multi-system parallelization is similar to
the mechanism explained in section 2. The key difference is that you need to
write a simple script that performs two actions:
- Uses SSH with authorized_keys to connect to every machine and retrieve
a tar archive of the /path/to/sync_dir/<fuzzer_id>/queue/ directories for
every <fuzzer_id> local to the machine. It's best to use a naming scheme
that includes host name in the fuzzer ID, so that you can do something
like:
a tar archive of the /path/to/sync_dir/<main_node(s)> directory local to
the machine.
It is best to use a naming scheme that includes host name and it's being
a main node (e.g. main1, main2) in the fuzzer ID, so that you can do
something like:
```sh
for s in {1..10}; do
ssh user@host${s} "tar -czf - sync/host${s}_fuzzid*/[qf]*" >host${s}.tgz
for host in `cat HOSTLIST`; do
ssh user@$host "tar -czf - sync/$host_main*/" > $host.tgz
done
```
- Distributes and unpacks these files on all the remaining machines, e.g.:
```sh
for s in {1..10}; do
for d in {1..10}; do
test "$s" = "$d" && continue
ssh user@host${d} 'tar -kxzf -' <host${s}.tgz
for srchost in `cat HOSTLIST`; do
for dsthost in `cat HOSTLIST`; do
test "$srchost" = "$dsthost" && continue
ssh user@$srchost 'tar -kxzf -' < $dsthost.tgz
done
done
```
There is an example of such a script in examples/distributed_fuzzing/;
you can also find a more featured, experimental tool developed by
Martijn Bogaard at:
There is an example of such a script in examples/distributed_fuzzing/.
https://github.com/MartijnB/disfuzz-afl
There are other (older) more featured, experimental tools:
* https://github.com/richo/roving
* https://github.com/MartijnB/disfuzz-afl
Another client-server implementation from Richo Healey is:
https://github.com/richo/roving
Note that these third-party tools are unsafe to run on systems exposed to the
Internet or to untrusted users.
However these do not support syncing just main nodes (yet).
When developing custom test case sync code, there are several optimizations
to keep in mind:
- The synchronization does not have to happen very often; running the
task every 30 minutes or so may be perfectly fine.
task every 60 minutes or even less often at later fuzzing stages is
fine
- There is no need to synchronize crashes/ or hangs/; you only need to
copy over queue/* (and ideally, also fuzzer_stats).
@ -179,19 +191,24 @@ to keep in mind:
- You do not want a "main" instance of afl-fuzz on every system; you should
run them all with -S, and just designate a single process somewhere within
the fleet to run with -M.
- Syncing is only necessary for the main nodes on a system. It is possible
to run main-less with only secondaries. However then you need to find out
which secondary took over the temporary role to be the main node. Look for
the `is_main_node` file in the fuzzer directories, eg. `sync-dir/hostname-*/is_main_node`
It is *not* advisable to skip the synchronization script and run the fuzzers
directly on a network filesystem; unexpected latency and unkillable processes
in I/O wait state can mess things up.
## 5) Remote monitoring and data collection
## 6) Remote monitoring and data collection
You can use screen, nohup, tmux, or something equivalent to run remote
instances of afl-fuzz. If you redirect the program's output to a file, it will
automatically switch from a fancy UI to more limited status reports. There is
also basic machine-readable information always written to the fuzzer_stats file
in the output directory. Locally, that information can be interpreted with
afl-whatsup.
also basic machine-readable information which is always written to the
fuzzer_stats file in the output directory. Locally, that information can be
interpreted with afl-whatsup.
In principle, you can use the status screen of the main (-M) instance to
monitor the overall fuzzing progress and decide when to stop. In this
@ -208,7 +225,7 @@ Keep in mind that crashing inputs are *not* automatically propagated to the
main instance, so you may still want to monitor for crashes fleet-wide
from within your synchronization or health checking scripts (see afl-whatsup).
## 6) Asymmetric setups
## 7) Asymmetric setups
It is perhaps worth noting that all of the following is permitted:
@ -224,7 +241,7 @@ It is perhaps worth noting that all of the following is permitted:
the discovered test cases can have synergistic effects and improve the
overall coverage.
(In this case, running one -M instance per each binary is a good plan.)
(In this case, running one -M instance per target is necessary.)
- Having some of the fuzzers invoke the binary in different ways.
For example, 'djpeg' supports several DCT modes, configurable with

View File

@ -73,9 +73,9 @@ static u8 *in_file, /* Minimizer input test case */
static u8 *in_data; /* Input data for trimming */
static u8 *buf2;
static s32 in_len;
static u32 map_size = MAP_SIZE;
static size_t buf2_len;
static s32 in_len;
static s32 buf2_len;
static u32 map_size = MAP_SIZE;
static volatile u8 stop_soon; /* Ctrl-C pressed? */
@ -272,7 +272,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
setenv("QEMU_SET_ENV", buf, 1);
ck_free(buf);
afl_free(buf);
} else {
@ -343,7 +343,7 @@ static void usage(u8 *argv0) {
}
int recv_testcase(int s, void **buf, size_t *max_len) {
int recv_testcase(int s, void **buf) {
u32 size;
s32 ret;
@ -358,7 +358,8 @@ int recv_testcase(int s, void **buf, size_t *max_len) {
if ((size & 0xff000000) != 0xff000000) {
*buf = ck_maybe_grow(buf, max_len, size);
*buf = afl_realloc((void **)&buf, size);
if (unlikely(!buf)) { PFATAL("Alloc"); }
received = 0;
// fprintf(stderr, "unCOMPRESS (%u)\n", size);
while (received < size &&
@ -370,7 +371,8 @@ int recv_testcase(int s, void **buf, size_t *max_len) {
#ifdef USE_DEFLATE
u32 clen;
size -= 0xff000000;
*buf = ck_maybe_grow(buf, max_len, size);
*buf = afl_realloc((void **)&buf, size);
if (unlikely(!buf)) { PFATAL("Alloc"); }
received = 0;
while (received < 4 &&
(ret = recv(s, &clen + received, 4 - received, 0)) > 0)
@ -379,15 +381,16 @@ int recv_testcase(int s, void **buf, size_t *max_len) {
// fprintf(stderr, "received clen information of %d\n", clen);
if (clen < 1)
FATAL("did not receive valid compressed len information: %u", clen);
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, clen);
buf2 = afl_realloc((void **)&buf2, clen);
buf2_len = clen;
if (unlikely(!buf2)) { PFATAL("Alloc"); }
received = 0;
while (received < clen &&
(ret = recv(s, buf2 + received, clen - received, 0)) > 0)
received += ret;
if (received != clen) FATAL("did not receive compressed information");
if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf,
*max_len,
&received) != LIBDEFLATE_SUCCESS)
size, &received) != LIBDEFLATE_SUCCESS)
FATAL("decompression failed");
// fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received);
// for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]);
@ -413,7 +416,6 @@ int recv_testcase(int s, void **buf, size_t *max_len) {
int main(int argc, char **argv_orig, char **envp) {
s32 opt, s, sock, on = 1, port = -1;
size_t max_len = 0;
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
char **use_argv;
struct sockaddr_in6 serveraddr, clientaddr;
@ -568,7 +570,8 @@ int main(int argc, char **argv_orig, char **envp) {
sharedmem_t shm = {0};
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
in_data = ck_maybe_grow((void **)&in_data, &max_len, 65536);
in_data = afl_realloc((void **)&in_data, 65536);
if (unlikely(!in_data)) { PFATAL("Alloc"); }
atexit(at_exit_handler);
setup_signal_handlers();
@ -639,7 +642,9 @@ int main(int argc, char **argv_orig, char **envp) {
#ifdef USE_DEFLATE
compressor = libdeflate_alloc_compressor(1);
decompressor = libdeflate_alloc_decompressor();
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, map_size + 16);
buf2 = afl_realloc((void **)&buf2, map_size + 16);
buf2_len = map_size + 16;
if (unlikely(!buf2)) { PFATAL("alloc"); }
lenptr = (u32 *)(buf2 + 4);
fprintf(stderr, "Compiled with compression support\n");
#endif
@ -664,7 +669,7 @@ int main(int argc, char **argv_orig, char **envp) {
#endif
while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) {
while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) {
// fprintf(stderr, "received %u\n", in_len);
(void)run_target(fsrv, use_argv, in_data, in_len, 1);
@ -697,9 +702,9 @@ int main(int argc, char **argv_orig, char **envp) {
afl_shm_deinit(&shm);
afl_fsrv_deinit(fsrv);
if (fsrv->target_path) { ck_free(fsrv->target_path); }
if (in_data) { ck_free(in_data); }
afl_free(in_data);
#if USE_DEFLATE
if (buf2) { ck_free(buf2); }
afl_free(buf2);
libdeflate_free_compressor(compressor);
libdeflate_free_decompressor(decompressor);
#endif

View File

@ -6,6 +6,8 @@
void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
if (Size < 5) return;
if (Data[0] == 'F')
if (Data[1] == 'A')
if (Data[2] == '$')
@ -16,12 +18,11 @@ void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
fprintf(stderr, "FUNC crc: %016llx len: %lu\n",
hash64((u8 *)Data, (unsigned int)Size,
(unsigned long long int)0xa5b35705),
Size);
if (Size < 5) return 0;
if (Size)
fprintf(stderr, "FUNC crc: %016llx len: %lu\n",
hash64((u8 *)Data, (unsigned int)Size,
(unsigned long long int)0xa5b35705),
Size);
crashme(Data, Size);

View File

@ -324,8 +324,8 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
}
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
void * scratch_buf = *buf1;
size_t scratch_size = *size1;

View File

@ -39,8 +39,11 @@ FUZZ_USER=bob
# Directory to synchronize
SYNC_DIR='/home/bob/sync_dir'
# Interval (seconds) between sync attempts
SYNC_INTERVAL=$((30 * 60))
# We only capture -M main nodes, set the name to your chosen naming scheme
MAIN_NAME='main'
# Interval (seconds) between sync attempts (eg one hour)
SYNC_INTERVAL=$((60 * 60))
if [ "$AFL_ALLOW_TMP" = "" ]; then
@ -63,7 +66,7 @@ while :; do
echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..."
ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \
"cd '$SYNC_DIR' && tar -czf - ${host}_*/[qf]*" >".sync_tmp/${host}.tgz"
"cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz"
done
@ -80,7 +83,7 @@ while :; do
echo " Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..."
ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \
"cd '$SYNC_DIR' && tar -xkzf -" <".sync_tmp/${src_host}.tgz"
"cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz"
done

View File

@ -24,7 +24,7 @@ PREFIX ?= /usr/local
HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin
DOC_PATH ?= $(PREFIX)/share/doc/afl
MAN_PATH ?= $(PREFIX)/man/man8
MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
@ -111,21 +111,21 @@ test_deps:
@echo "[+] All set and ready to build."
afl-common.o: ../src/afl-common.c
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $(CPPFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
ln -sf afl-gcc-fast ../afl-g++-fast
../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps
$(CC) $(CFLAGS_SAFE) -fPIC -c $< -o $@
$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -fPIC -c $< -o $@
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr

View File

@ -24,7 +24,7 @@ PREFIX ?= /usr/local
HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin
DOC_PATH ?= $(PREFIX)/share/doc/afl
MAN_PATH ?= $(PREFIX)/man/man8
MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
VERSION:sh= grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2

View File

@ -126,6 +126,9 @@
#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
#define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf)
extern s8 interesting_8[INTERESTING_8_LEN];
extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
extern s32
@ -285,16 +288,19 @@ enum {
enum {
/* 00 */ PY_FUNC_INIT,
/* 01 */ PY_FUNC_FUZZ,
/* 02 */ PY_FUNC_POST_PROCESS,
/* 03 */ PY_FUNC_INIT_TRIM,
/* 04 */ PY_FUNC_POST_TRIM,
/* 05 */ PY_FUNC_TRIM,
/* 06 */ PY_FUNC_HAVOC_MUTATION,
/* 07 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
/* 08 */ PY_FUNC_QUEUE_GET,
/* 09 */ PY_FUNC_QUEUE_NEW_ENTRY,
/* 10 */ PY_FUNC_DEINIT,
/* 01 */ PY_FUNC_DEINIT,
/* FROM HERE ON BELOW ALL ARE OPTIONAL */
/* 02 */ PY_OPTIONAL = 2,
/* 02 */ PY_FUNC_FUZZ = 2,
/* 03 */ PY_FUNC_FUZZ_COUNT,
/* 04 */ PY_FUNC_POST_PROCESS,
/* 05 */ PY_FUNC_INIT_TRIM,
/* 06 */ PY_FUNC_POST_TRIM,
/* 07 */ PY_FUNC_TRIM,
/* 08 */ PY_FUNC_HAVOC_MUTATION,
/* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
/* 10 */ PY_FUNC_QUEUE_GET,
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
PY_FUNC_COUNT
};
@ -350,7 +356,8 @@ typedef struct afl_env_vars {
afl_cal_fast, afl_cycle_schedules, afl_expand_havoc;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_skip_crashes, *afl_preload;
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
*afl_max_det_extras;
} afl_env_vars_t;
@ -503,7 +510,8 @@ typedef struct afl_state {
useless_at_start, /* Number of useless starting paths */
var_byte_count, /* Bitmap bytes with var behavior */
current_entry, /* Current queue entry ID */
havoc_div; /* Cycle count divisor for havoc */
havoc_div, /* Cycle count divisor for havoc */
max_det_extras; /* deterministic extra count (dicts)*/
u64 total_crashes, /* Total number of crashes */
unique_crashes, /* Crashes with unique signatures */
@ -572,7 +580,6 @@ typedef struct afl_state {
// growing buf
struct queue_entry **queue_buf;
size_t queue_size;
struct queue_entry **top_rated; /* Top entries for bitmap bytes */
@ -622,7 +629,7 @@ typedef struct afl_state {
/* plot file saves from last run */
u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md;
u64 plot_prev_qc, plot_prev_uc, plot_prev_uh;
u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed;
u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
double stats_avg_exec;
@ -633,24 +640,18 @@ typedef struct afl_state {
/*needed for afl_fuzz_one */
// TODO: see which we can reuse
u8 * out_buf;
size_t out_size;
u8 *out_buf;
u8 * out_scratch_buf;
size_t out_scratch_size;
u8 *out_scratch_buf;
u8 * eff_buf;
size_t eff_size;
u8 *eff_buf;
u8 * in_buf;
size_t in_size;
u8 *in_buf;
u8 * in_scratch_buf;
size_t in_scratch_size;
u8 *in_scratch_buf;
u8 * ex_buf;
size_t ex_size;
u32 custom_mutators_count;
u8 *ex_buf;
u32 custom_mutators_count;
list_t custom_mutator_list;
@ -666,7 +667,6 @@ struct custom_mutator {
char * name_short;
void * dh;
u8 * post_process_buf;
size_t post_process_size;
u8 stacked_custom_prob, stacked_custom;
void *data; /* custom mutator data ptr */
@ -682,6 +682,24 @@ struct custom_mutator {
*/
void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
/**
* This method is called just before fuzzing a queue entry with the custom
* mutator, and receives the initial buffer. It should return the number of
* fuzzes to perform.
*
* A value of 0 means no fuzzing of this queue entry.
*
* The function is now allowed to change the data.
*
* (Optional)
*
* @param data pointer returned in afl_custom_init for this fuzz case
* @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
*/
u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size);
/**
* Perform custom mutations on a given input
*
@ -870,6 +888,7 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf,
struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
void finalize_py_module(void *);
u32 fuzz_count_py(void *, const u8 *, size_t);
size_t post_process_py(void *, u8 *, size_t, u8 **);
s32 init_trim_py(void *, u8 *, size_t);
s32 post_trim_py(void *, u8);
@ -918,6 +937,7 @@ u8 has_new_bits(afl_state_t *, u8 *);
void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
void load_extras(afl_state_t *, u8 *);
void add_extra(afl_state_t *afl, u8 *mem, u32 len);
void maybe_add_auto(afl_state_t *, u8 *, u32);
void save_auto(afl_state_t *);
void load_auto(afl_state_t *);
@ -925,6 +945,7 @@ void destroy_extras(afl_state_t *);
/* Stats */
void write_setup_file(afl_state_t *, u32, char **);
void write_stats_file(afl_state_t *, double, double, double);
void maybe_update_plot_file(afl_state_t *, double, double);
void show_stats(afl_state_t *);
@ -1007,7 +1028,18 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
}
return rand_next(afl) % limit;
/* Modulo is biased - we don't want our fuzzing to be biased so let's do it
right. See:
https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator
*/
u64 unbiased_rnd;
do {
unbiased_rnd = rand_next(afl);
} while (unlikely(unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit))));
return unbiased_rnd % limit;
}

View File

@ -30,12 +30,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "config.h"
#include "types.h"
#include "debug.h"
/* Initial size used for ck_maybe_grow */
/* Initial size used for afl_realloc */
#define INITIAL_GROWTH_SIZE (64)
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
@ -76,10 +77,6 @@
\
} while (0)
/* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */
@ -149,15 +146,6 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
}
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
repeated small reallocs without complicating the user code). */
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
return DFL_ck_realloc(orig, size);
}
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
static inline u8 *DFL_ck_strdup(u8 *str) {
@ -183,7 +171,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_free DFL_ck_free
@ -239,10 +226,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
#define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
/* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256
/* Sanity-checking macros for pointers. */
#define CHECK_PTR(_p) \
@ -402,29 +385,6 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
}
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
repeated small reallocs without complicating the user code). */
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
#ifndef DEBUG_BUILD
if (orig) {
CHECK_PTR(orig);
if (ALLOC_S(orig) >= size) return orig;
size += ALLOC_BLK_INC;
}
#endif /* !DEBUG_BUILD */
return DFL_ck_realloc(orig, size);
}
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
static inline u8 *DFL_ck_strdup(u8 *str) {
@ -458,7 +418,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_free DFL_ck_free
@ -528,8 +487,8 @@ static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func,
/* No space available - allocate more. */
TRK[bucket] = DFL_ck_realloc_block(
TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
TRK[bucket] = DFL_ck_realloc(TRK[bucket],
(TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char *)file;
@ -604,16 +563,6 @@ static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file,
}
static inline void *TRK_ck_realloc_block(void *orig, u32 size, const char *file,
const char *func, u32 line) {
void *ret = DFL_ck_realloc_block(orig, size);
TRK_free_buf(orig, file, func, line);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
u32 line) {
@ -641,9 +590,6 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
#define ck_realloc(_p1, _p2) \
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc_block(_p1, _p2) \
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
@ -657,11 +603,14 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
*/
static inline size_t next_pow2(size_t in) {
if (in == 0 || in > (size_t)-1) {
// Commented this out as this behavior doesn't change, according to unittests
// if (in == 0 || in > (size_t)-1) {
return 0; /* avoid undefined behaviour under-/overflow */
}
//
// return 0; /* avoid undefined behaviour under-/overflow
// */
//
// }
size_t out = in - 1;
out |= out >> 1;
@ -673,6 +622,35 @@ static inline size_t next_pow2(size_t in) {
}
/* AFL alloc buffer, the struct is here so we don't need to do fancy ptr
* arithmetics */
struct afl_alloc_buf {
/* The complete allocated size, including the header of len
* AFL_ALLOC_SIZE_OFFSET */
size_t complete_size;
/* ptr to the first element of the actual buffer */
u8 buf[0];
};
#define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf))
/* Returs 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);
}
/* Gets the maximum size of the buf contents (ptr->complete_size -
* AFL_ALLOC_SIZE_OFFSET) */
static inline size_t afl_alloc_bufsize(void *buf) {
return afl_alloc_bufptr(buf)->complete_size - AFL_ALLOC_SIZE_OFFSET;
}
/* This function makes sure *size is > size_needed after call.
It will realloc *buf otherwise.
*size will grow exponentially as per:
@ -680,71 +658,68 @@ static inline size_t next_pow2(size_t in) {
Will return NULL and free *buf if size_needed is <1 or realloc failed.
@return For convenience, this function returns *buf.
*/
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
static inline void *afl_realloc(void **buf, size_t size_needed) {
struct afl_alloc_buf *new_buf = NULL;
size_t current_size = 0;
size_t next_size = 0;
if (likely(*buf)) {
/* the size is always stored at buf - 1*size_t */
new_buf = afl_alloc_bufptr(*buf);
current_size = new_buf->complete_size;
}
size_needed += AFL_ALLOC_SIZE_OFFSET;
/* No need to realloc */
if (likely(size_needed && *size >= size_needed)) { return *buf; }
if (likely(current_size >= size_needed)) { return *buf; }
/* No initial size was set */
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
if (size_needed < INITIAL_GROWTH_SIZE) {
/* grow exponentially */
size_t next_size = next_pow2(size_needed);
next_size = INITIAL_GROWTH_SIZE;
/* handle overflow and zero size_needed */
if (!next_size) { next_size = size_needed; }
} else {
/* grow exponentially */
next_size = next_pow2(size_needed);
/* handle overflow: fall back to the original size_needed */
if (unlikely(!next_size)) { next_size = size_needed; }
}
/* alloc */
*buf = realloc(*buf, next_size);
*size = *buf ? next_size : 0;
new_buf = realloc(new_buf, next_size);
if (unlikely(!new_buf)) {
*buf = NULL;
return NULL;
}
new_buf->complete_size = next_size;
*buf = (void *)(new_buf->buf);
return *buf;
}
/* This function makes sure *size is > size_needed after call.
It will realloc *buf otherwise.
*size will grow exponentially as per:
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
Will FATAL if size_needed is <1.
@return For convenience, this function returns *buf.
*/
static inline void *ck_maybe_grow(void **buf, size_t *size,
size_t size_needed) {
static inline void afl_free(void *buf) {
/* Oops. found a bug? */
if (unlikely(size_needed < 1)) { FATAL("cannot grow to non-positive size"); }
/* No need to realloc */
if (likely(*size >= size_needed)) { return *buf; }
/* No initial size was set */
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
/* grow exponentially */
size_t next_size = next_pow2(size_needed);
/* handle overflow */
if (!next_size) { next_size = size_needed; }
/* alloc */
*buf = ck_realloc(*buf, next_size);
*size = next_size;
return *buf;
if (buf) { free(afl_alloc_bufptr(buf)); }
}
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
static inline void afl_swap_bufs(void **buf1, void **buf2) {
void * scratch_buf = *buf1;
size_t scratch_size = *size1;
void *scratch_buf = *buf1;
*buf1 = *buf2;
*size1 = *size2;
*buf2 = scratch_buf;
*size2 = scratch_size;
}

View File

@ -110,5 +110,11 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
/* Reads the map size from ENV */
u32 get_map_size(void);
/* create a stream file */
FILE *create_ffile(u8 *fn);
/* create a file */
s32 create_file(u8 *fn);
#endif

View File

@ -28,7 +28,7 @@
/* Version string: */
// c = release, d = volatile github dev, e = experimental branch
#define VERSION "++2.67c"
#define VERSION "++2.68c"
/******************************************************
* *

View File

@ -48,6 +48,7 @@ static char *afl_environment_variables[] = {
"AFL_GCC_INSTRUMENT_FILE",
"AFL_GCJ",
"AFL_HANG_TMOUT",
"AFL_FORKSRV_INIT_TMOUT",
"AFL_HARDEN",
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
"AFL_IMPORT_FIRST",
@ -102,6 +103,7 @@ static char *afl_environment_variables[] = {
"AFL_NO_X86", // not really an env but we dont want to warn on it
"AFL_MAP_SIZE",
"AFL_MAPSIZE",
"AFL_MAX_DET_EXTRAS",
"AFL_PATH",
"AFL_PERFORMANCE_FILE",
"AFL_PRELOAD",
@ -110,12 +112,16 @@ static char *afl_environment_variables[] = {
"AFL_QEMU_COMPCOV_DEBUG",
"AFL_QEMU_DEBUG_MAPS",
"AFL_QEMU_DISABLE_CACHE",
"AFL_QEMU_DRIVER_NO_HOOK",
"AFL_QEMU_PERSISTENT_ADDR",
"AFL_QEMU_PERSISTENT_CNT",
"AFL_QEMU_PERSISTENT_GPR",
"AFL_QEMU_PERSISTENT_HOOK",
"AFL_QEMU_PERSISTENT_RET",
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
"AFL_QEMU_PERSISTENT_EXITS",
"AFL_QEMU_INST_RANGES",
"AFL_QEMU_SNAPSHOT",
"AFL_QUIET",
"AFL_RANDOM_ALLOC_CANARY",
"AFL_REAL_PATH",

View File

@ -56,6 +56,7 @@ typedef struct afl_forkserver {
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 */
u32 snapshot; /* is snapshot feature used */
u64 mem_limit; /* Memory cap for child (MB) */
@ -91,7 +92,7 @@ typedef struct afl_forkserver {
u8 *afl_ptr; /* for autodictionary: afl ptr */
void (*autodict_func)(void *afl_ptr, u8 *mem, u32 len);
void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len);
} afl_forkserver_t;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ all: libdislocator.so
VPATH = ..
libdislocator.so: libdislocator.so.c ../config.h
$(CC) $(CFLAGS) -shared -fPIC libdislocator.so.c -o ../$@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC libdislocator.so.c -o ../$@ $(LDFLAGS)
.NOTPARALLEL: clean

View File

@ -16,7 +16,7 @@
PREFIX ?= /usr/local
HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH ?= $(PREFIX)/share/doc/afl
MAN_PATH ?= $(PREFIX)/man/man8
MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
@ -70,7 +70,7 @@ all: $(TARGETS)
VPATH = ..
libtokencap.so: libtokencap.so.c ../config.h
$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
.NOTPARALLEL: clean

View File

@ -275,8 +275,8 @@ static void __tokencap_load_mappings(void) {
for (c = map; r > 0; c++, r -= sizeof(prmap_t)) {
__tokencap_ro[__tokencap_ro_cnt].st = c->pr_vaddr;
__tokencap_ro[__tokencap_ro_cnt].en = c->pr_vaddr + c->pr_size;
__tokencap_ro[__tokencap_ro_cnt].st = (void *)c->pr_vaddr;
__tokencap_ro[__tokencap_ro_cnt].en = (void *)(c->pr_vaddr + c->pr_size);
if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;

View File

@ -24,10 +24,12 @@ HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin
DOC_PATH ?= $(PREFIX)/share/doc/afl
MISC_PATH ?= $(PREFIX)/share/afl
MAN_PATH ?= $(PREFIX)/man/man8
MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
ifeq "$(shell uname)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
@ -215,6 +217,12 @@ ifeq "$(LLVM_LTO)" "1"
endif
endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
else
AFL_CLANG_DEBUG_PREFIX = ""
endif
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
@ -224,7 +232,8 @@ CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \
-DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function \
$(AFL_CLANG_DEBUG_PREFIX)
override CFLAGS += $(CFLAGS_SAFE)
ifdef AFL_TRACE_PC
@ -274,7 +283,7 @@ ifeq "$(TEST_MMAP)" "1"
LDFLAGS += -Wno-deprecated-declarations
endif
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so ../SanitizerCoverageLTO.so
# If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" ""
@ -329,10 +338,10 @@ endif
@echo "[+] All set and ready to build."
afl-common.o: ../src/afl-common.c
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
$(CC) $(CLANG_CFL) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
$(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
ln -sf afl-clang-fast ../afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@ -342,7 +351,7 @@ endif
endif
afl-llvm-common.o: afl-llvm-common.cc afl-llvm-common.h
$(CXX) $(CFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc afl-llvm-common.o | test_deps
-$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
@ -360,20 +369,20 @@ endif
../afl-ld-lto: afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
endif
../SanitizerCoverageLTO.so: SanitizerCoverageLTO.so.cc
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
endif
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
$(CLANG_BIN) $(CFLAGS_SAFE) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
@$(CLANG_BIN) $(CFLAGS_SAFE) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
@$(CLANG_BIN) $(CFLAGS_SAFE) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
endif
../afl-llvm-lto-instrim.so: afl-llvm-lto-instrim.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
endif
# laf
@ -392,20 +401,20 @@ endif
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
document:
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -Wno-unused-result -fPIC -c $< -o $@
$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
@ -424,7 +433,7 @@ all_done: test_build
install: all
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-ld-lto ]; then set -e; install -m 755 ../afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
@ -432,16 +441,18 @@ install: all
if [ -f ../split-compares-pass.so ]; then set -e; install -m 755 ../split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../split-switches-pass.so ]; then set -e; install -m 755 ../split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../cmplog-instructions-pass.so ]; then set -e; install -m 755 ../cmplog-*-pass.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../SanitizerCoverageLTO.so ]; then set -e; install -m 755 ../SanitizerCoverageLTO.so $${DESTDIR}$(HELPER_PATH); fi
set -e; install -m 644 ../dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
set -e; if [ -f ../afl-clang-fast ] ; then ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
set -e; if [ -f ../afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md
install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md
vpath % ..
%.8: %
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
@echo .TH $* 8 $(BUILD_DATE) "afl++" > ../$@
@echo .SH NAME >> ../$@
@echo .B $* >> ../$@
@echo -n ".B $* \- " >> ../$@
@../$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ../$@
@echo >> ../$@
@echo .SH SYNOPSIS >> ../$@
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@

View File

@ -132,10 +132,6 @@ struct InsTrim : public ModulePass {
}
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
unsigned int PrevLocSize = 0;
char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
@ -181,10 +177,16 @@ struct InsTrim : public ModulePass {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
// IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
IntegerType *IntLocTy =
IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
if (ngram_size)
PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
#if LLVM_VERSION_MAJOR >= 12
,
false
#endif
);
#endif
/* Get globals for the SHM region and the previous location. Note that
@ -241,7 +243,7 @@ struct InsTrim : public ModulePass {
for (unsigned I = 0; I < PrevLocSize - 1; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
for (int I = PrevLocSize; I < PrevLocVecSize; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);

View File

@ -19,15 +19,6 @@ see how often the loop has been rerun.
This again is a tradeoff for speed for less path information.
To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
There is an additional optimization option that skips single block
functions. In 95% of the C targets and (guess) 50% of the C++ targets
it is good to enable this, as otherwise pointless instrumentation occurs.
The corner case where we want this instrumentation is when vtable/call table
is used and the index to that vtable/call table is not set in specific
basic blocks.
To enable skipping these (most of the time) unnecessary instrumentations set
`AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1`
## Background
The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]

File diff suppressed because it is too large Load Diff

View File

@ -347,11 +347,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode) {
if (cmplog_mode)
unsetenv("AFL_LLVM_LTO_AUTODICTIONARY");
else
setenv("AFL_LLVM_LTO_AUTODICTIONARY", "1", 1);
#if defined(AFL_CLANG_LDPATH) && LLVM_VERSION_MAJOR >= 12
u8 *ld_ptr = strrchr(AFL_REAL_LD, '/');
if (!ld_ptr) ld_ptr = "ld.lld";
@ -363,16 +358,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
/*
The current LTO instrim mode is not good, so we disable it
if (instrument_mode == INSTRUMENT_CFG)
cc_params[cc_par_cnt++] =
alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so",
obj_path); else
*/
if (instrument_mode == INSTRUMENT_CFG)
cc_params[cc_par_cnt++] =
alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
else
cc_params[cc_par_cnt++] = alloc_printf(
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
cc_params[cc_par_cnt++] = alloc_printf(
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
cc_params[cc_par_cnt++] = lto_flag;
} else {
@ -678,9 +670,11 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
#ifndef __APPLE__
if (!shared_linking)
cc_params[cc_par_cnt++] =
alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
#endif
#endif
@ -756,7 +750,13 @@ int main(int argc, char **argv, char **envp) {
if (strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
strncasecmp(ptr, "classic", strlen("classic")) == 0) {
if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
if (instrument_mode == INSTRUMENT_LTO) {
instrument_mode = INSTRUMENT_CLASSIC;
lto_mode = 1;
} else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
instrument_mode = INSTRUMENT_AFL;
else
FATAL("main instrumentation mode already set with %s",
@ -813,13 +813,25 @@ int main(int argc, char **argv, char **envp) {
if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) {
ptr += strlen("ngram");
while (*ptr && (*ptr < '0' || *ptr > '9'))
while (*ptr && (*ptr < '0' || *ptr > '9')) {
ptr++;
if (!*ptr)
if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL)
}
if (!*ptr) {
ptr = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ptr || !*ptr) {
FATAL(
"you must set the NGRAM size with (e.g. for value 2) "
"AFL_LLVM_INSTRUMENT=ngram-2");
}
}
ngram_size = atoi(ptr);
if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
FATAL(
@ -848,11 +860,18 @@ int main(int argc, char **argv, char **envp) {
callname = "afl-clang-lto";
if (!instrument_mode) {
instrument_mode = INSTRUMENT_LTO;
instrument_mode = INSTRUMENT_CFG;
ptr = instrument_mode_string[instrument_mode];
}
} else if (instrument_mode == INSTRUMENT_LTO ||
instrument_mode == INSTRUMENT_CLASSIC) {
lto_mode = 1;
callname = "afl-clang-lto";
} else {
if (!be_quiet)
@ -978,8 +997,11 @@ int main(int argc, char **argv, char **envp) {
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
"AFL_INST_RATIO: percentage of branches to instrument\n"
#if LLVM_VERSION_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
"AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
"AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
@ -989,9 +1011,8 @@ int main(int argc, char **argv, char **envp) {
"AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
"function calls\n"
"AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
"AFL_LLVM_INSTRUMENT_FILE: enable the instrument file listing "
"(selective "
"instrumentation)\n"
"AFL_LLVM_INSTRUMENT_ALLOW/AFL_LLVM_INSTRUMENT_DENY: enable instrument"
"allow/deny listing (selective instrumentation)\n"
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
"AFL_PATH: path to instrumenting pass and runtime "
"(afl-llvm-rt.*o)\n"

View File

@ -344,9 +344,10 @@ static std::string getSourceName(llvm::Function *F) {
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
if (Loc) {
StringRef instFilename;
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
StringRef instFilename = cDILoc->getFilename();
if (cDILoc) { instFilename = cDILoc->getFilename(); }
if (instFilename.str().empty()) {

View File

@ -1,951 +0,0 @@
/*
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
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 library is plugged into LLVM when invoking clang through afl-clang-fast
or afl-clang-lto with AFL_LLVM_INSTRUMENT=CFG or =INSTRIM
*/
#define AFL_LLVM_PASS
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <unordered_set>
#include <list>
#include <string>
#include <fstream>
#include <set>
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/ValueTracking.h"
#include "MarkNodes.h"
#include "afl-llvm-common.h"
#include "config.h"
#include "debug.h"
using namespace llvm;
static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
cl::init(false));
static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
cl::init(false));
namespace {
struct InsTrimLTO : public ModulePass {
protected:
uint32_t function_minimum_size = 1;
char * skip_nozero = NULL;
int afl_global_id = 1, autodictionary = 1;
uint32_t inst_blocks = 0, inst_funcs = 0;
uint64_t map_addr = 0x10000;
public:
static char ID;
InsTrimLTO() : ModulePass(ID) {
char *ptr;
if (getenv("AFL_DEBUG")) debug = 1;
if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE)
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
ptr, MAP_SIZE - 1);
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
ModulePass::getAnalysisUsage(AU);
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
}
StringRef getPassName() const override {
return "InstTrim LTO Instrumentation";
}
bool runOnModule(Module &M) override {
char be_quiet = 0;
char * ptr;
uint32_t locations = 0, functions = 0;
setvbuf(stdout, NULL, _IONBF, 0);
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "InsTrimLTO" VERSION cRST
" by csienslab and Marc \"vanHauser\" Heuse\n");
} else
be_quiet = 1;
/* Process environment variables */
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
uint64_t val;
if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
map_addr = 0;
} else if (map_addr == 0) {
FATAL(
"AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used "
"together");
} else if (strncmp(ptr, "0x", 2) != 0) {
map_addr = 0x10000; // the default
} else {
val = strtoull(ptr, NULL, 16);
if (val < 0x100 || val > 0xffffffff00000000) {
FATAL(
"AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
"0xffffffff00000000");
}
map_addr = val;
}
}
if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); }
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
getenv("LOOPHEAD") != NULL) {
LoopHeadOpt = true;
}
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
// this is our default
MarkSetOpt = true;
/* Initialize LLVM instrumentation */
LLVMContext & C = M.getContext();
std::vector<std::string> dictionary;
std::vector<CallInst *> calls;
DenseMap<Value *, std::string *> valueMap;
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
/* Get/set globals for the SHM region. */
GlobalVariable *AFLMapPtr = NULL;
Value * MapPtrFixed = NULL;
if (!map_addr) {
AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
} else {
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
MapPtrFixed =
ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Ty));
}
if (autodictionary) {
/* Some implementation notes.
*
* We try to handle 3 cases:
* - memcmp("foo", arg, 3) <- literal string
* - static char globalvar[] = "foo";
* memcmp(globalvar, arg, 3) <- global variable
* - char localvar[] = "foo";
* memcmp(locallvar, arg, 3) <- local variable
*
* The local variable case is the hardest. We can only detect that
* case if there is no reassignment or change in the variable.
* And it might not work across llvm version.
* What we do is hooking the initializer function for local variables
* (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
* variable. And if that variable is then used in a compare function
* we use that noted string.
* This seems not to work for tokens that have a size <= 4 :-(
*
* - if the compared length is smaller than the string length we
* save the full string. This is likely better for fuzzing but
* might be wrong in a few cases depending on optimizers
*
* - not using StringRef because there is a bug in the llvm 11
* checkout I am using which sometimes points to wrong strings
*
* Over and out. Took me a full day. damn. mh/vh
*/
for (Function &F : M) {
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
bool isStrcmp = true;
bool isMemcmp = true;
bool isStrncmp = true;
bool isStrcasecmp = true;
bool isStrncasecmp = true;
bool isIntMemcpy = true;
bool addedNull = false;
uint8_t optLen = 0;
Function *Callee = callInst->getCalledFunction();
if (!Callee) continue;
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
std::string FuncName = Callee->getName().str();
isStrcmp &= !FuncName.compare("strcmp");
isMemcmp &= !FuncName.compare("memcmp");
isStrncmp &= !FuncName.compare("strncmp");
isStrcasecmp &= !FuncName.compare("strcasecmp");
isStrncasecmp &= !FuncName.compare("strncasecmp");
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp
* function prototype */
FunctionType *FT = Callee->getFunctionType();
isStrcmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isStrcasecmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isMemcmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0)->isPointerTy() &&
FT->getParamType(1)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy();
isStrncmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
isStrncasecmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* is a str{n,}{case,}cmp/memcmp, check if we have
* str{case,}cmp(x, "const") or str{case,}cmp("const", x)
* strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x,
* ..) memcmp(x, "const", ..) or memcmp("const", x, ..) */
Value *Str1P = callInst->getArgOperand(0),
*Str2P = callInst->getArgOperand(1);
std::string Str1, Str2;
StringRef TmpStr;
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty())
HasStr1 = false;
else
Str1 = TmpStr.str();
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
if (TmpStr.empty())
HasStr2 = false;
else
Str2 = TmpStr.str();
if (debug)
fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
Str2P->getName().str().c_str(), Str2.c_str(),
HasStr2 == true ? "true" : "false");
// we handle the 2nd parameter first because of llvm memcpy
if (!HasStr2) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var =
dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
}
}
}
}
}
// for the internal memcpy routine we only care for the second
// parameter and are not reporting anything.
if (isIntMemcpy == true) {
if (HasStr2 == true) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = Str2.size();
uint64_t optLength = ilen->getZExtValue();
if (literalLength + 1 == optLength) {
Str2.append("\0", 1); // add null byte
addedNull = true;
}
}
valueMap[Str1P] = new std::string(Str2);
if (debug)
fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
continue;
}
continue;
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr2) {
std::string *strng = valueMap[Str2P];
if (strng && !strng->empty()) {
Str2 = *strng;
HasStr2 = true;
if (debug)
fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
Str2P);
}
}
if (!HasStr1) {
auto Ptr = dyn_cast<ConstantExpr>(Str1P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var =
dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
}
}
}
}
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr1) {
std::string *strng = valueMap[Str1P];
if (strng && !strng->empty()) {
Str1 = *strng;
HasStr1 = true;
if (debug)
fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
Str1P);
}
}
/* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) continue;
std::string thestring;
if (HasStr1)
thestring = Str1;
else
thestring = Str2;
optLen = thestring.length();
if (isMemcmp || isStrncmp || isStrncasecmp) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = optLen;
optLen = ilen->getZExtValue();
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
}
}
}
// add null byte if this is a string compare function and a null
// was not already added
if (addedNull == false && !isMemcmp) {
thestring.append("\0", 1); // add null byte
optLen++;
}
if (!be_quiet) {
std::string outstring;
fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
(unsigned int)thestring.length());
for (uint8_t i = 0; i < thestring.length(); i++) {
uint8_t c = thestring[i];
if (c <= 32 || c >= 127)
fprintf(stderr, "\\x%02x", c);
else
fprintf(stderr, "%c", c);
}
fprintf(stderr, "\"\n");
}
// we take the longer string, even if the compare was to a
// shorter part. Note that depending on the optimizer of the
// compiler this can be wrong, but it is more likely that this
// is helping the fuzzer
if (optLen != thestring.length()) optLen = thestring.length();
if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
if (optLen < MIN_AUTO_EXTRA) // too short? skip
continue;
dictionary.push_back(thestring.substr(0, optLen));
}
}
}
}
}
/* InsTrim instrumentation starts here */
u64 total_rs = 0;
u64 total_hs = 0;
for (Function &F : M) {
if (debug) {
uint32_t bb_cnt = 0;
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);
}
// if the function below our minimum size skip it (1 or 2)
if (F.size() < function_minimum_size) continue;
if (isIgnoreFunction(&F)) continue;
functions++;
// the instrument file list check
AttributeList Attrs = F.getAttributes();
if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {
if (debug)
fprintf(stderr,
"DEBUG: Function %s is not the instrument file listed\n",
F.getName().str().c_str());
continue;
}
std::unordered_set<BasicBlock *> MS;
if (!MarkSetOpt) {
for (auto &BB : F) {
MS.insert(&BB);
}
total_rs += F.size();
} else {
auto Result = markNodes(&F);
auto RS = Result.first;
auto HS = Result.second;
MS.insert(RS.begin(), RS.end());
if (!LoopHeadOpt) {
MS.insert(HS.begin(), HS.end());
total_rs += MS.size();
} else {
DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
DominatorTreeWrapperPass * DTWP =
&getAnalysis<DominatorTreeWrapperPass>(F);
auto DT = &DTWP->getDomTree();
total_rs += RS.size();
total_hs += HS.size();
for (BasicBlock *BB : HS) {
bool Inserted = false;
for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {
auto Edge = BasicBlockEdge(*BI, BB);
if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
EdgeSet.insert({*BI, BB});
Inserted = true;
break;
}
}
if (!Inserted) {
MS.insert(BB);
total_rs += 1;
total_hs -= 1;
}
}
for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
auto PredBB = I->first;
auto SuccBB = I->second;
auto NewBB = SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT,
nullptr, nullptr, false);
MS.insert(NewBB);
}
}
}
for (BasicBlock &BB : F) {
auto PI = pred_begin(&BB);
auto PE = pred_end(&BB);
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
Value * L = NULL;
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
if (PI == PE) {
L = ConstantInt::get(Int32Ty, afl_global_id++);
locations++;
} else {
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
DenseMap<BasicBlock *, unsigned> PredMap;
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
BasicBlock *PBB = *PI;
auto It = PredMap.insert({PBB, afl_global_id++});
unsigned Label = It.first->second;
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
locations++;
}
L = PN;
}
/* Load SHM pointer */
Value *MapPtrIdx;
if (map_addr) {
MapPtrIdx = IRB.CreateGEP(MapPtrFixed, L);
} else {
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
MapPtrIdx = IRB.CreateGEP(MapPtr, L);
}
/* Update bitmap */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *Incr = IRB.CreateAdd(Counter, One);
if (skip_nozero == NULL) {
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
}
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// done :)
inst_blocks++;
}
}
// save highest location ID to global variable
// do this after each function to fail faster
if (!be_quiet && afl_global_id > MAP_SIZE &&
afl_global_id > FS_OPT_MAX_MAPSIZE) {
uint32_t pow2map = 1, map = afl_global_id;
while ((map = map >> 1))
pow2map++;
WARNF(
"We have %u blocks to instrument but the map size is only %u. Either "
"edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
"afl-fuzz and llvm_mode and then make this target - or set "
"AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
"target.",
afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id);
}
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
Function *f = M.getFunction("__afl_auto_init_globals");
if (!f) {
fprintf(stderr,
"Error: init function could not be found (this should not "
"happen)\n");
exit(-1);
}
BasicBlock *bb = &f->getEntryBlock();
if (!bb) {
fprintf(stderr,
"Error: init function does not have an EntryBlock (this should "
"not happen)\n");
exit(-1);
}
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (map_addr) {
GlobalVariable *AFLMapAddrFixed =
new GlobalVariable(M, Int64Ty, true, GlobalValue::ExternalLinkage,
0, "__afl_map_addr");
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
uint32_t write_loc = afl_global_id;
if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
GlobalVariable *AFLFinalLoc =
new GlobalVariable(M, Int32Ty, true, GlobalValue::ExternalLinkage,
0, "__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (dictionary.size()) {
size_t memlen = 0, count = 0, offset = 0;
char * ptr;
for (auto token : dictionary) {
memlen += token.length();
count++;
}
if (!be_quiet)
printf("AUTODICTIONARY: %lu string%s found\n", count,
count == 1 ? "" : "s");
if (count) {
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
memlen + count);
exit(-1);
}
count = 0;
for (auto token : dictionary) {
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
ptr[offset++] = (uint8_t)token.length();
memcpy(ptr + offset, token.c_str(), token.length());
offset += token.length();
count++;
}
}
GlobalVariable *AFLDictionaryLen = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
"__afl_dictionary_len");
ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
StoreInst * StoreDictLen =
IRB.CreateStore(const_len, AFLDictionaryLen);
StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
GlobalVariable *AFLInternalDictionary = new GlobalVariable(
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))),
"__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))));
AFLInternalDictionary->setConstant(true);
GlobalVariable *AFLDictionary = new GlobalVariable(
M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
Value *AFLDictPtr =
IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
StoreDict->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
}
// count basic blocks for comparison with classic instrumentation
u32 edges = 0;
for (auto &F : M) {
if (F.size() < function_minimum_size) continue;
for (auto &BB : F) {
bool would_instrument = false;
for (BasicBlock *Pred : predecessors(&BB)) {
int count = 0;
for (BasicBlock *Succ : successors(Pred))
if (Succ != NULL) count++;
if (count > 1) would_instrument = true;
}
if (would_instrument == true) edges++;
}
}
/* Say something nice. */
if (!be_quiet) {
if (!inst_blocks)
WARNF("No instrumentation targets found.");
else {
char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
OKF("Instrumented %u locations for %u edges in %u functions (%llu, "
"%llu) with no collisions (on "
"average %llu collisions would be in afl-gcc/afl-clang-fast for %u "
"edges) (%s mode).",
inst_blocks, locations, functions, total_rs, total_hs,
calculateCollisions(edges), edges, modeline);
}
}
return true;
}
}; // end of struct InsTrim
} // end of anonymous namespace
char InsTrimLTO::ID = 0;
static void registerInsTrimLTO(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new InsTrimLTO());
}
static RegisterPass<InsTrimLTO> X("afl-lto-instrim",
"afl++ InsTrim LTO instrumentation pass",
false, false);
static RegisterStandardPasses RegisterInsTrimLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerInsTrimLTO);

View File

@ -87,7 +87,7 @@ class AFLLTOPass : public ModulePass {
bool runOnModule(Module &M) override;
protected:
int afl_global_id = 1, autodictionary = 0;
int afl_global_id = 1, autodictionary = 1;
uint32_t function_minimum_size = 1;
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
uint64_t map_addr = 0x10000;
@ -135,15 +135,11 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
if (getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1;
// we make this the default as the fixed map has problems with
// defered forkserver, early constructors, ifuncs and maybe more
/*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
map_addr = 0;
if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2;
if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
uint64_t val;
@ -378,16 +374,29 @@ bool AFLLTOPass::runOnModule(Module &M) {
std::string Str1, Str2;
StringRef TmpStr;
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty())
if (TmpStr.empty()) {
HasStr1 = false;
else
} else {
HasStr1 = true;
Str1 = TmpStr.str();
}
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
if (TmpStr.empty())
if (TmpStr.empty()) {
HasStr2 = false;
else
} else {
HasStr2 = true;
Str2 = TmpStr.str();
}
if (debug)
fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
@ -602,17 +611,41 @@ bool AFLLTOPass::runOnModule(Module &M) {
for (auto &BB : F) {
if (F.size() == 1) {
InsBlocks.push_back(&BB);
continue;
}
uint32_t succ = 0;
if (F.size() == 1) InsBlocks.push_back(&BB);
for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB); SI != SE;
++SI)
if ((*SI)->size() > 0) succ++;
if (succ < 2) // no need to instrument
continue;
if (BlockList.size()) {
int skip = 0;
for (uint32_t k = 0; k < BlockList.size(); k++) {
if (&BB == BlockList[k]) {
if (debug)
fprintf(stderr,
"DEBUG: Function %s skipping BB with/after __afl_loop\n",
F.getName().str().c_str());
skip = 1;
}
}
if (skip) continue;
}
InsBlocks.push_back(&BB);
}
@ -631,28 +664,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
uint32_t fs = origBB->getParent()->size();
uint32_t countto;
if (BlockList.size()) {
int skip = 0;
for (uint32_t k = 0; k < BlockList.size(); k++) {
if (origBB == BlockList[k]) {
if (debug)
fprintf(
stderr,
"DEBUG: Function %s skipping BB with/after __afl_loop\n",
F.getName().str().c_str());
skip = 1;
}
}
if (skip) continue;
}
for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
SI != SE; ++SI) {

View File

@ -182,10 +182,6 @@ bool AFLCoverage::runOnModule(Module &M) {
#endif
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
unsigned PrevLocSize = 0;
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
@ -225,8 +221,14 @@ bool AFLCoverage::runOnModule(Module &M) {
PrevLocSize = 1;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
if (ngram_size)
PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
#if LLVM_VERSION_MAJOR >= 12
,
false
#endif
);
#endif
/* Get globals for the SHM region and the previous location. Note that
@ -282,7 +284,7 @@ bool AFLCoverage::runOnModule(Module &M) {
for (unsigned I = 0; I < PrevLocSize - 1; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
for (int I = PrevLocSize; I < PrevLocVecSize; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);

View File

@ -339,7 +339,7 @@ static void __afl_map_shm(void) {
if (__afl_area_ptr == MAP_FAILED) {
fprintf(stderr, "can not aquire mmap for address %p\n",
fprintf(stderr, "can not acquire mmap for address %p\n",
(void *)__afl_map_addr);
exit(1);

View File

@ -356,6 +356,8 @@ bool SplitComparesTransform::simplifyIntSignedness(Module &M) {
* all signed compares to icomps vector */
for (auto &F : M) {
if (!isInInstrumentList(&F)) continue;
for (auto &BB : F) {
for (auto &IN : BB) {
@ -542,6 +544,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
* functions were executed only these four predicates should exist */
for (auto &F : M) {
if (!isInInstrumentList(&F)) continue;
for (auto &BB : F) {
for (auto &IN : BB) {
@ -1052,6 +1056,8 @@ size_t SplitComparesTransform::splitIntCompares(Module &M, unsigned bitw) {
* were executed only these four predicates should exist */
for (auto &F : M) {
if (!isInInstrumentList(&F)) continue;
for (auto &BB : F) {
for (auto &IN : BB) {
@ -1272,7 +1278,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
if (!be_quiet) {
errs() << "Split-floatingpoint-compare-pass: " << count
<< " FP comparisons splitted\n";
<< " FP comparisons split\n";
}
@ -1290,7 +1296,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
count = splitIntCompares(M, bitw);
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
<< " splitted\n";
<< " split\n";
bitw >>= 1;
#if LLVM_VERSION_MAJOR > 3 || \
@ -1301,7 +1307,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
count = splitIntCompares(M, bitw);
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
<< " splitted\n";
<< " split\n";
bitw >>= 1;
#if LLVM_VERSION_MAJOR > 3 || \
@ -1312,7 +1318,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
count = splitIntCompares(M, bitw);
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
<< " splitted\n";
<< " split\n";
bitw >>= 1;
break;

View File

@ -16,7 +16,7 @@
PREFIX ?= /usr/local
HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH ?= $(PREFIX)/share/doc/afl
MAN_PATH ?= $(PREFIX)/man/man8
MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)

View File

@ -152,7 +152,7 @@ static void edit_params(int argc, char **argv) {
/* The Apple case is a bit different... */
if (!strcmp(argv[i], "-arch") && i + 1 < argc) {
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
if (!strcmp(argv[i + 1], "x86_64"))
use_64bit = 1;

View File

@ -877,3 +877,36 @@ u32 get_map_size(void) {
}
/* Create a stream file */
FILE *create_ffile(u8 *fn) {
s32 fd;
FILE *f;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
f = fdopen(fd, "w");
if (!f) { PFATAL("fdopen() failed"); }
return f;
}
/* Create a file */
s32 create_file(u8 *fn) {
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
return fd;
}

View File

@ -79,6 +79,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->use_stdin = 1;
fsrv->no_unlink = 0;
fsrv->exec_tmout = EXEC_TIMEOUT;
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
fsrv->mem_limit = MEM_LIMIT;
fsrv->out_file = NULL;
@ -101,6 +102,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->out_fd = from->out_fd;
fsrv_to->dev_null_fd = from->dev_null_fd;
fsrv_to->exec_tmout = from->exec_tmout;
fsrv_to->init_tmout = from->init_tmout;
fsrv_to->mem_limit = from->mem_limit;
fsrv_to->map_size = from->map_size;
fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz;
@ -115,6 +117,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->out_file = NULL;
fsrv_to->init_child_func = fsrv_exec_child;
// Note: do not copy ->add_extra_func
list_append(&fsrv_list, fsrv_to);
@ -237,6 +240,23 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
if (!child_pid) { // New child
close(fsrv->out_dir_fd);
close(fsrv->dev_null_fd);
close(fsrv->dev_urandom_fd);
if (fsrv->plot_file != NULL) {
fclose(fsrv->plot_file);
fsrv->plot_file = NULL;
}
// enable terminating on sigpipe in the childs
struct sigaction sa;
memset((char *)&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigaction(SIGPIPE, &sa, NULL);
signal(SIGCHLD, old_sigchld_handler);
// FORKSRV_FD is for communication with AFL, we don't need it in the
// child.
@ -358,11 +378,16 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* CHILD PROCESS */
// enable terminating on sigpipe in the childs
struct sigaction sa;
memset((char *)&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigaction(SIGPIPE, &sa, NULL);
struct rlimit r;
/* Umpf. On OpenBSD, the default fd limit for root users is set to
soft 128. Let's try to fix that... */
if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
r.rlim_cur = FORKSRV_FD + 2;
@ -429,7 +454,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
close(fsrv->dev_null_fd);
close(fsrv->dev_urandom_fd);
if (fsrv->plot_file != NULL) { fclose(fsrv->plot_file); }
if (fsrv->plot_file != NULL) {
fclose(fsrv->plot_file);
fsrv->plot_file = NULL;
}
/* This should improve performance a bit, since it stops the linker from
doing extra work post-fork(). */
@ -516,15 +546,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
rlen = 0;
if (fsrv->exec_tmout) {
u32 time_ms =
read_s32_timed(fsrv->fsrv_st_fd, &status,
fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p);
u32 time_ms = read_s32_timed(fsrv->fsrv_st_fd, &status, fsrv->init_tmout,
stop_soon_p);
if (!time_ms) {
kill(fsrv->fsrv_pid, SIGKILL);
} else if (time_ms > fsrv->exec_tmout * FORK_WAIT_MULT) {
} else if (time_ms > fsrv->init_tmout) {
fsrv->last_run_timed_out = 1;
kill(fsrv->fsrv_pid, SIGKILL);
@ -630,9 +659,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
if (fsrv->autodict_func == NULL || fsrv->afl_ptr == NULL) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
// this is not afl-fuzz - we deny and return
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
@ -715,8 +744,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->autodict_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
@ -939,7 +968,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
s32 fd = fsrv->out_fd;
if (fsrv->out_file) {
if (!fsrv->use_stdin) {
if (fsrv->no_unlink) {
@ -962,7 +991,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
ck_write(fd, buf, len, fsrv->out_file);
if (!fsrv->out_file) {
if (fsrv->use_stdin) {
if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
lseek(fd, 0, SEEK_SET);

View File

@ -152,8 +152,10 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
/* Okay, let's allocate memory and copy data between "...", handling
\xNN escaping, \\, and \". */
afl->extras = ck_realloc_block(
afl->extras, (afl->extras_cnt + 1) * sizeof(struct extra_data));
afl->extras =
afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
@ -225,6 +227,36 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
}
static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len,
u8 *dir) {
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); }
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
if (max_len > 32) {
WARNF("Some tokens are relatively large (%s) - consider trimming.",
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len));
}
if (afl->extras_cnt > afl->max_det_extras) {
OKF("More than %d tokens - will use them probabilistically.",
afl->max_det_extras);
}
}
/* Read extras from the extras directory and sort them by size. */
void load_extras(afl_state_t *afl, u8 *dir) {
@ -254,7 +286,8 @@ void load_extras(afl_state_t *afl, u8 *dir) {
if (errno == ENOTDIR) {
load_extras_file(afl, dir, &min_len, &max_len, dict_level);
goto check_and_sort;
extras_check_and_sort(afl, min_len, max_len, dir);
return;
}
@ -286,8 +319,8 @@ void load_extras(afl_state_t *afl, u8 *dir) {
if (st.st_size > MAX_DICT_FILE) {
FATAL(
"Extra '%s' is too big (%s, limit is %s)", fn,
WARNF(
"Extra '%s' is very big (%s, limit is %s)", fn,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
@ -296,8 +329,10 @@ void load_extras(afl_state_t *afl, u8 *dir) {
if (min_len > st.st_size) { min_len = st.st_size; }
if (max_len < st.st_size) { max_len = st.st_size; }
afl->extras = ck_realloc_block(
afl->extras, (afl->extras_cnt + 1) * sizeof(struct extra_data));
afl->extras =
afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
afl->extras[afl->extras_cnt].data = ck_alloc(st.st_size);
afl->extras[afl->extras_cnt].len = st.st_size;
@ -317,30 +352,7 @@ void load_extras(afl_state_t *afl, u8 *dir) {
closedir(d);
check_and_sort:
if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); }
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
if (max_len > 32) {
WARNF("Some tokens are relatively large (%s) - consider trimming.",
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len));
}
if (afl->extras_cnt > MAX_DET_EXTRAS) {
WARNF("More than %d tokens - will use them probabilistically.",
MAX_DET_EXTRAS);
}
extras_check_and_sort(afl, min_len, max_len, dir);
}
@ -358,6 +370,48 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
}
/* Adds a new extra / dict entry. Used for LTO autodict. */
void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
if (len > MAX_DICT_FILE) {
WARNF("Extra '%.*s' is very big (%s, limit is %s)", (int)len, mem,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
} else if (len > 32) {
WARNF("Extra '%.*s' is pretty large, consider trimming.", (int)len, mem);
}
afl->extras = afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
afl->extras[afl->extras_cnt].data = ck_alloc(len);
afl->extras[afl->extras_cnt].len = len;
memcpy(afl->extras[afl->extras_cnt].data, mem, len);
afl->extras_cnt++;
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
/* We only want to print this once */
if (afl->extras_cnt == afl->max_det_extras + 1) {
OKF("More than %d tokens - will use them probabilistically.",
afl->max_det_extras);
}
}
/* Maybe add automatic extra. */
void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) {
@ -573,7 +627,7 @@ void destroy_extras(afl_state_t *afl) {
}
ck_free(afl->extras);
afl_free(afl->extras);
}

View File

@ -256,18 +256,18 @@ void bind_to_free_cpu(afl_state_t *afl) {
}
for (i = 0; i < proccount; i++) {
for (i = 0; i < (s32)proccount; i++) {
#if defined(__FreeBSD__)
if (!strcmp(procs[i].ki_comm, "idle")) continue;
// fix when ki_oncpu = -1
int oncpu;
s32 oncpu;
oncpu = procs[i].ki_oncpu;
if (oncpu == -1) oncpu = procs[i].ki_lastcpu;
if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
if (oncpu != -1 && oncpu < (s32)sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
cpu_used[oncpu] = 1;
#elif defined(__DragonFly__)
@ -1841,24 +1841,26 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) {
void setup_stdio_file(afl_state_t *afl) {
u8 *fn;
if (afl->file_extension) {
fn = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
afl->fsrv.out_file =
alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
} else {
fn = alloc_printf("%s/.cur_input", afl->tmp_dir);
afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir);
}
unlink(fn); /* Ignore errors */
unlink(afl->fsrv.out_file); /* Ignore errors */
afl->fsrv.out_fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600);
afl->fsrv.out_fd = open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
if (afl->fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fn); }
if (afl->fsrv.out_fd < 0) {
ck_free(fn);
PFATAL("Unable to create '%s'", afl->fsrv.out_file);
}
}

View File

@ -122,9 +122,8 @@ void destroy_custom_mutators(afl_state_t *afl) {
if (el->post_process_buf) {
ck_free(el->post_process_buf);
afl_free(el->post_process_buf);
el->post_process_buf = NULL;
el->post_process_size = 0;
}
@ -167,6 +166,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
}
/* "afl_custom_fuzz_count", optional */
mutator->afl_custom_fuzz_count = dlsym(dh, "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)

View File

@ -364,8 +364,6 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) {
#endif /* !IGNORE_FINDS */
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
/* Take the current entry from the queue, fuzz it for a while. This
function is a tad too long... returns 0 if fuzzed successfully, 1 if
skipped or bailed out. */
@ -384,9 +382,6 @@ u8 fuzz_one_original(afl_state_t *afl) {
u8 a_collect[MAX_AUTO_EXTRA];
u32 a_len = 0;
/* Not pretty, but saves a lot of writing */
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
#ifdef IGNORE_FINDS
/* In IGNORE_FINDS mode, skip any entries that weren't in the
@ -484,7 +479,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
single byte anyway, so it wouldn't give us any performance or memory usage
benefits. */
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
afl->subseq_tmouts = 0;
@ -800,7 +796,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
/* Initialize effector map for the next step (see comments below). Always
flag first and last byte as doing something. */
eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len));
eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
if (unlikely(!eff_map)) { PFATAL("alloc"); }
eff_map[0] = 1;
if (EFF_APOS(len - 1) != 0) {
@ -1512,13 +1509,13 @@ skip_interest:
for (j = 0; j < afl->extras_cnt; ++j) {
/* Skip extras probabilistically if afl->extras_cnt > MAX_DET_EXTRAS. Also
skip them if there's no room to insert the payload, if the token
/* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS.
Also skip them if there's no room to insert the payload, if the token
is redundant, or if its entire span has no bytes set in the effector
map. */
if ((afl->extras_cnt > MAX_DET_EXTRAS &&
rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) ||
if ((afl->extras_cnt > afl->max_det_extras &&
rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) ||
afl->extras[j].len > len - i ||
!memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) ||
!memchr(eff_map + EFF_APOS(i), 1,
@ -1557,7 +1554,8 @@ skip_interest:
orig_hit_cnt = new_hit_cnt;
ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE);
ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
for (i = 0; i <= (u32)len; ++i) {
@ -1674,7 +1672,7 @@ custom_mutator_stage:
if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
const u32 max_seed_size = MAX_FILE;
const u32 max_seed_size = MAX_FILE, saved_max = afl->stage_max;
orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
@ -1682,103 +1680,123 @@ custom_mutator_stage:
if (el->afl_custom_fuzz) {
if (el->afl_custom_fuzz_count)
afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
else
afl->stage_max = saved_max;
has_custom_fuzz = true;
afl->stage_short = el->name_short;
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
++afl->stage_cur) {
if (afl->stage_max) {
struct queue_entry *target;
u32 tid;
u8 * new_buf;
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
++afl->stage_cur) {
retry_external_pick:
/* Pick a random other queue entry for passing to external API */
struct queue_entry *target;
u32 tid;
u8 * new_buf;
do {
retry_external_pick:
/* Pick a random other queue entry for passing to external API */
tid = rand_below(afl, afl->queued_paths);
do {
} while (tid == afl->current_entry && afl->queued_paths > 1);
tid = rand_below(afl, afl->queued_paths);
target = afl->queue;
} while (tid == afl->current_entry && afl->queued_paths > 1);
while (tid >= 100) {
target = afl->queue;
target = target->next_100;
tid -= 100;
while (tid >= 100) {
}
while (tid--) {
target = target->next;
}
/* Make sure that the target has a reasonable length. */
while (target && (target->len < 2 || target == afl->queue_cur) &&
afl->queued_paths > 3) {
target = target->next;
++afl->splicing_with;
}
if (!target) { goto retry_external_pick; }
/* Read the additional testcase into a new buffer. */
fd = open(target->fname, O_RDONLY);
if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); }
new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len);
ck_read(fd, new_buf, target->len, target->fname);
close(fd);
u8 *mutated_buf = NULL;
size_t mutated_size =
el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
target->len, max_seed_size);
if (unlikely(!mutated_buf)) {
FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
}
if (mutated_size > 0) {
if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
goto abandon_entry;
target = target->next_100;
tid -= 100;
}
/* If we're finding new stuff, let's run for a bit longer, limits
permitting. */
while (tid--) {
if (afl->queued_paths != havoc_queued) {
target = target->next;
if (perf_score <= afl->havoc_max_mult * 100) {
}
afl->stage_max *= 2;
perf_score *= 2;
/* Make sure that the target has a reasonable length. */
while (target && (target->len < 2 || target == afl->queue_cur) &&
afl->queued_paths > 3) {
target = target->next;
++afl->splicing_with;
}
if (!target) { goto retry_external_pick; }
/* Read the additional testcase into a new buffer. */
fd = open(target->fname, O_RDONLY);
if (unlikely(fd < 0)) {
PFATAL("Unable to open '%s'", target->fname);
}
new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
ck_read(fd, new_buf, target->len, target->fname);
close(fd);
u8 *mutated_buf = NULL;
size_t mutated_size =
el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
target->len, max_seed_size);
if (unlikely(!mutated_buf)) {
FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
}
if (mutated_size > 0) {
if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
goto abandon_entry;
}
havoc_queued = afl->queued_paths;
if (!el->afl_custom_fuzz_count) {
/* If we're finding new stuff, let's run for a bit longer, limits
permitting. */
if (afl->queued_paths != havoc_queued) {
if (perf_score <= afl->havoc_max_mult * 100) {
afl->stage_max *= 2;
perf_score *= 2;
}
havoc_queued = afl->queued_paths;
}
}
}
}
/* `(afl->)out_buf` may have been changed by the call to custom_fuzz
*/
/* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs
* Memcpy.
*/
memcpy(out_buf, in_buf, len);
/* `(afl->)out_buf` may have been changed by the call to custom_fuzz */
/* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy.
*/
memcpy(out_buf, in_buf, len);
}
}
@ -1908,7 +1926,8 @@ havoc_stage:
temp_len = new_len;
if (out_buf != custom_havoc_buf) {
ck_maybe_grow(BUF_PARAMS(out), temp_len);
afl_realloc(AFL_BUF_PARAM(out), temp_len);
if (unlikely(!afl->out_buf)) { PFATAL("alloc"); }
memcpy(out_buf, custom_havoc_buf, temp_len);
}
@ -2147,7 +2166,8 @@ havoc_stage:
clone_to = rand_below(afl, temp_len);
new_buf =
ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len);
afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
/* Head */
@ -2172,7 +2192,7 @@ havoc_stage:
memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
temp_len - clone_to);
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
out_buf = new_buf;
new_buf = NULL;
temp_len += clone_len;
@ -2287,7 +2307,8 @@ havoc_stage:
if (temp_len + extra_len >= MAX_FILE) { break; }
out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
/* Tail */
memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
@ -2343,7 +2364,8 @@ havoc_stage:
}
u32 new_len = target->len;
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len);
u8 *new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), new_len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
ck_read(fd, new_buf, new_len, target->fname);
@ -2383,7 +2405,8 @@ havoc_stage:
clone_to = rand_below(afl, temp_len);
u8 *temp_buf =
ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len);
afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
if (unlikely(!temp_buf)) { PFATAL("alloc"); }
/* Head */
@ -2397,7 +2420,7 @@ havoc_stage:
memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
temp_len - clone_to);
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
out_buf = temp_buf;
temp_len += clone_len;
@ -2418,7 +2441,8 @@ havoc_stage:
/* out_buf might have been mangled a bit, so let's restore it to its
original size and shape. */
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
temp_len = len;
memcpy(out_buf, in_buf, len);
@ -2513,7 +2537,8 @@ retry_splicing:
if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); }
new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len);
new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
ck_read(fd, new_buf, target->len, target->fname);
@ -2535,10 +2560,11 @@ retry_splicing:
len = target->len;
memcpy(new_buf, in_buf, split_at);
swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch));
afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch));
in_buf = new_buf;
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
memcpy(out_buf, in_buf, len);
goto custom_mutator_stage;
@ -2679,7 +2705,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
single byte anyway, so it wouldn't give us any performance or memory usage
benefits. */
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
afl->subseq_tmouts = 0;
@ -3001,7 +3028,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
/* Initialize effector map for the next step (see comments below). Always
flag first and last byte as doing something. */
eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len));
eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
if (unlikely(!eff_map)) { PFATAL("alloc"); }
eff_map[0] = 1;
if (EFF_APOS(len - 1) != 0) {
@ -3713,13 +3741,13 @@ skip_interest:
for (j = 0; j < afl->extras_cnt; ++j) {
/* Skip extras probabilistically if afl->extras_cnt > MAX_DET_EXTRAS. Also
skip them if there's no room to insert the payload, if the token
/* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS.
Also skip them if there's no room to insert the payload, if the token
is redundant, or if its entire span has no bytes set in the effector
map. */
if ((afl->extras_cnt > MAX_DET_EXTRAS &&
rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) ||
if ((afl->extras_cnt > afl->max_det_extras &&
rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) ||
afl->extras[j].len > len - i ||
!memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) ||
!memchr(eff_map + EFF_APOS(i), 1,
@ -3758,7 +3786,8 @@ skip_interest:
orig_hit_cnt = new_hit_cnt;
ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE);
ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
for (i = 0; i <= (u32)len; ++i) {
@ -4196,8 +4225,9 @@ pacemaker_fuzzing:
clone_to = rand_below(afl, temp_len);
new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch),
temp_len + clone_len);
new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
temp_len + clone_len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
/* Head */
@ -4223,7 +4253,7 @@ pacemaker_fuzzing:
memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
temp_len - clone_to);
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
out_buf = new_buf;
temp_len += clone_len;
MOpt_globals.cycles_v2[STAGE_Clone75] += 1;
@ -4340,7 +4370,8 @@ pacemaker_fuzzing:
if (temp_len + extra_len >= MAX_FILE) break;
out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
/* Tail */
memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
@ -4373,7 +4404,8 @@ pacemaker_fuzzing:
/* out_buf might have been mangled a bit, so let's restore it to its
original size and shape. */
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
temp_len = len;
memcpy(out_buf, in_buf, len);
@ -4518,7 +4550,8 @@ pacemaker_fuzzing:
if (fd < 0) { PFATAL("Unable to open '%s'", target->fname); }
new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len);
new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
ck_read(fd, new_buf, target->len, target->fname);
@ -4545,9 +4578,10 @@ pacemaker_fuzzing:
len = target->len;
memcpy(new_buf, in_buf, split_at);
swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch));
afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch));
in_buf = new_buf;
out_buf = ck_maybe_grow(BUF_PARAMS(out), len);
out_buf = afl_realloc(AFL_BUF_PARAM(out), len);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
memcpy(out_buf, in_buf, len);
goto havoc_stage_puppet;
@ -4880,5 +4914,3 @@ u8 fuzz_one(afl_state_t *afl) {
}
#undef BUF_PARAMS

View File

@ -40,9 +40,7 @@ static void *unsupported(afl_state_t *afl, unsigned int seed) {
/* sorry for this makro...
it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */
#define BUF_PARAMS(name) \
(void **)&((py_mutator_t *)py_mutator)->name##_buf, \
&((py_mutator_t *)py_mutator)->name##_size
#define BUF_PARAMS(name) (void **)&((py_mutator_t *)py_mutator)->name##_buf
static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
u8 *add_buf, size_t add_buf_size, size_t max_size) {
@ -97,7 +95,8 @@ 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 = ck_maybe_grow(BUF_PARAMS(fuzz), mutated_size);
*out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
Py_DECREF(py_value);
@ -145,6 +144,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_FUZZ_COUNT] =
PyObject_GetAttrString(py_module, "fuzz_count");
if (!py_functions[PY_FUNC_FUZZ])
WARNF("fuzz function not found in python module");
py_functions[PY_FUNC_POST_PROCESS] =
@ -170,27 +171,20 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
if (py_idx == PY_FUNC_POST_PROCESS) {
// Implenting the post_process API is optional for now
if (PyErr_Occurred()) { PyErr_Print(); }
} else if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
// Implementing the trim API is optional for now
if (PyErr_Occurred()) { PyErr_Print(); }
py_notrim = 1;
} else if ((py_idx >= PY_FUNC_HAVOC_MUTATION) &&
} else if (py_idx >= PY_OPTIONAL) {
(py_idx <= PY_FUNC_QUEUE_NEW_ENTRY)) {
// Only _init and _deinit are not optional currently
// Implenting the havoc and queue API is optional for now
if (PyErr_Occurred()) { PyErr_Print(); }
} else {
if (PyErr_Occurred()) { PyErr_Print(); }
fprintf(stderr,
"Cannot find/call function with index %d in external "
"Python module.\n",
@ -317,7 +311,6 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
mutator = ck_alloc(sizeof(struct custom_mutator));
mutator->post_process_buf = NULL;
mutator->post_process_size = 0;
mutator->name = module_name;
ACTF("Loading Python mutator library from '%s'...", module_name);
@ -349,6 +342,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
}
if (py_functions[PY_FUNC_FUZZ_COUNT]) {
mutator->afl_custom_fuzz_count = fuzz_count_py;
}
if (py_functions[PY_FUNC_POST_TRIM]) {
mutator->afl_custom_post_trim = post_trim_py;
@ -419,7 +418,11 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
py_out_buf_size = PyByteArray_Size(py_value);
ck_maybe_grow(BUF_PARAMS(post_process), py_out_buf_size);
if (unlikely(!afl_realloc(BUF_PARAMS(post_process), py_out_buf_size))) {
PFATAL("alloc");
}
memcpy(py->post_process_buf, PyByteArray_AsString(py_value),
py_out_buf_size);
@ -475,6 +478,44 @@ s32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) {
}
u32 fuzz_count_py(void *py_mutator, const u8 *buf, size_t buf_size) {
PyObject *py_args, *py_value;
py_args = PyTuple_New(1);
py_value = PyByteArray_FromStringAndSize(buf, buf_size);
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_FUZZ_COUNT], py_args);
Py_DECREF(py_args);
if (py_value != NULL) {
#if PY_MAJOR_VERSION >= 3
u32 retcnt = (u32)PyLong_AsLong(py_value);
#else
u32 retcnt = PyInt_AsLong(py_value);
#endif
Py_DECREF(py_value);
return retcnt;
} else {
PyErr_Print();
FATAL("Call failed");
}
}
s32 post_trim_py(void *py_mutator, u8 success) {
PyObject *py_args, *py_value;
@ -527,7 +568,8 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
if (py_value != NULL) {
ret = PyByteArray_Size(py_value);
*out_buf = ck_maybe_grow(BUF_PARAMS(trim), ret);
*out_buf = afl_realloc(BUF_PARAMS(trim), ret);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
memcpy(*out_buf, PyByteArray_AsString(py_value), ret);
Py_DECREF(py_value);
@ -592,7 +634,8 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
} else {
/* A new buf is needed... */
*out_buf = ck_maybe_grow(BUF_PARAMS(havoc), mutated_size);
*out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size);
if (unlikely(!out_buf)) { PFATAL("alloc"); }
}

View File

@ -26,8 +26,6 @@
#include <limits.h>
#include <ctype.h>
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
/* Mark deterministic checks as done for a particular queue entry. We use the
.state file to avoid repeating deterministic fuzzing when resuming aborted
scans. */
@ -140,9 +138,9 @@ static u8 check_if_text(struct queue_entry *q) {
}
// non-overlong 2-byte
if (((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF)) &&
len - offset > 1) {
if (len - offset > 1 &&
((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
offset += 2;
utf8++;
@ -248,8 +246,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
struct queue_entry **queue_buf = ck_maybe_grow(
BUF_PARAMS(queue), afl->queued_paths * sizeof(struct queue_entry *));
struct queue_entry **queue_buf = afl_realloc(
AFL_BUF_PARAM(queue), afl->queued_paths * sizeof(struct queue_entry *));
if (unlikely(!queue_buf)) { PFATAL("alloc"); }
queue_buf[afl->queued_paths - 1] = q;
afl->last_path_time = get_cur_time();

View File

@ -264,7 +264,8 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
static long long strntoll(const char *str, size_t sz, char **end, int base) {
static int strntoll(const char *str, size_t sz, char **end, int base,
long long *out) {
char buf[64];
long long ret;
@ -272,24 +273,22 @@ static long long strntoll(const char *str, size_t sz, char **end, int base) {
for (; beg && sz && *beg == ' '; beg++, sz--) {};
if (!sz || sz >= sizeof(buf)) {
if (end) *end = (char *)str;
return 0;
}
if (!sz) return 1;
if (sz >= sizeof(buf)) sz = sizeof(buf) - 1;
memcpy(buf, beg, sz);
buf[sz] = '\0';
ret = strtoll(buf, end, base);
if (ret == LLONG_MIN || ret == LLONG_MAX) return ret;
if ((ret == LLONG_MIN || ret == LLONG_MAX) && errno == ERANGE) return 1;
if (end) *end = (char *)beg + (*end - buf);
return ret;
*out = ret;
return 0;
}
static unsigned long long strntoull(const char *str, size_t sz, char **end,
int base) {
static int strntoull(const char *str, size_t sz, char **end, int base,
unsigned long long *out) {
char buf[64];
unsigned long long ret;
@ -298,23 +297,20 @@ static unsigned long long strntoull(const char *str, size_t sz, char **end,
for (; beg && sz && *beg == ' '; beg++, sz--)
;
if (!sz || sz >= sizeof(buf)) {
if (end) *end = (char *)str;
return 0;
}
if (!sz) return 1;
if (sz >= sizeof(buf)) sz = sizeof(buf) - 1;
memcpy(buf, beg, sz);
buf[sz] = '\0';
ret = strtoull(buf, end, base);
if (ret == ULLONG_MAX && errno == ERANGE) return 1;
if (end) *end = (char *)beg + (*end - buf);
return ret;
*out = ret;
return 0;
}
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 pattern, u64 repl, u64 o_pattern, u32 idx,
u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse,
@ -338,14 +334,14 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u8 use_num = 0, use_unum = 0;
unsigned long long unum;
long long num;
if (afl->queue_cur->is_ascii) {
endptr = buf_8;
num = strntoll(buf_8, len - idx, (char **)&endptr, 0);
if (endptr == buf_8) {
if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) {
unum = strntoull(buf_8, len - idx, (char **)&endptr, 0);
if (endptr == buf_8) use_unum = 1;
if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum))
use_unum = 1;
} else
@ -358,7 +354,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
size_t old_len = endptr - buf_8;
size_t num_len = snprintf(NULL, 0, "%lld", num);
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
memcpy(new_buf, buf, idx);
snprintf(new_buf + idx, num_len, "%lld", num);
@ -371,7 +368,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
size_t old_len = endptr - buf_8;
size_t num_len = snprintf(NULL, 0, "%llu", unum);
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
memcpy(new_buf, buf, idx);
snprintf(new_buf + idx, num_len, "%llu", unum);

View File

@ -135,8 +135,6 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
}
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
/* The same, but with an adjustable gap. Used for trimming. */
static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
@ -149,7 +147,8 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
This memory is used to carry out the post_processing(if present) after copying
the testcase by removing the gaps. This can break though
*/
u8 *mem_trimmed = ck_maybe_grow(BUF_PARAMS(out_scratch), len - skip_len + 1);
u8 *mem_trimmed = afl_realloc(AFL_BUF_PARAM(out_scratch), len - skip_len + 1);
if (unlikely(!mem_trimmed)) { PFATAL("alloc"); }
ssize_t new_size = len - skip_len;
void * new_mem = mem;
@ -288,8 +287,6 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
}
#undef BUF_PARAMS
/* Calibrate a new test case. This is done when processing the input directory
to warn about flaky or otherwise problematic test cases early on; and when
new paths are discovered to detect variable behavior and so on. */

View File

@ -114,7 +114,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->fsrv.map_size = map_size;
// afl_state_t is not available in forkserver.c
afl->fsrv.afl_ptr = (void *)afl;
afl->fsrv.autodict_func = (void (*)(void *, u8 *, u32)) & maybe_add_auto;
afl->fsrv.add_extra_func = (void (*)(void *, u8 *, u32)) & add_extra;
afl->cal_cycles = CAL_CYCLES;
afl->cal_cycles_long = CAL_CYCLES_LONG;
@ -349,6 +349,20 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_preload =
(u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_MAX_DET_EXTRAS",
afl_environment_variable_len)) {
afl->afl_env.afl_max_det_extras =
(u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_FORKSRV_INIT_TMOUT",
afl_environment_variable_len)) {
afl->afl_env.afl_forksrv_init_tmout =
(u8 *)get_afl_env(afl_environment_variables[i]);
}
} else {
@ -421,13 +435,13 @@ void afl_state_deinit(afl_state_t *afl) {
if (afl->pass_stats) { ck_free(afl->pass_stats); }
if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); }
if (afl->queue_buf) { free(afl->queue_buf); }
if (afl->out_buf) { free(afl->out_buf); }
if (afl->out_scratch_buf) { free(afl->out_scratch_buf); }
if (afl->eff_buf) { free(afl->eff_buf); }
if (afl->in_buf) { free(afl->in_buf); }
if (afl->in_scratch_buf) { free(afl->in_scratch_buf); }
if (afl->ex_buf) { free(afl->ex_buf); }
afl_free(afl->queue_buf);
afl_free(afl->out_buf);
afl_free(afl->out_scratch_buf);
afl_free(afl->eff_buf);
afl_free(afl->in_buf);
afl_free(afl->in_scratch_buf);
afl_free(afl->ex_buf);
ck_free(afl->virgin_bits);
ck_free(afl->virgin_tmout);

View File

@ -24,8 +24,64 @@
*/
#include "afl-fuzz.h"
#include "envs.h"
#include <limits.h>
/* Write fuzzer setup file */
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
char *val;
u8 fn[PATH_MAX];
snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
FILE *f = create_ffile(fn);
u32 i;
fprintf(f, "# environment variables:\n");
u32 s_afl_env = (u32)
sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) -
1U;
for (i = 0; i < s_afl_env; ++i) {
if ((val = getenv(afl_environment_variables[i])) != NULL) {
fprintf(f, "%s=%s\n", afl_environment_variables[i], val);
}
}
fprintf(f, "# command line:\n");
size_t j;
for (i = 0; i < argc; ++i) {
if (i) fprintf(f, " ");
if (index(argv[i], '\'')) {
fprintf(f, "'");
for (j = 0; j < strlen(argv[i]); j++)
if (argv[i][j] == '\'')
fprintf(f, "'\"'\"'");
else
fprintf(f, "%c", argv[i][j]);
fprintf(f, "'");
} else {
fprintf(f, "'%s'", argv[i]);
}
}
fprintf(f, "\n");
fclose(f);
(void)(afl_environment_deprecated);
}
/* Update stats file for unattended monitoring. */
void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
@ -35,21 +91,13 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
struct rusage rus;
#endif
unsigned long long int cur_time = get_cur_time();
u8 fn[PATH_MAX];
s32 fd;
FILE * f;
u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
u64 cur_time = get_cur_time();
u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
u8 fn[PATH_MAX];
FILE *f;
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
f = fdopen(fd, "w");
if (!f) { PFATAL("fdopen() failed"); }
f = create_ffile(fn);
/* Keep last values in case we're called from another context
where exec/sec stats and such are not readily available. */
@ -163,11 +211,12 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
? ""
: "default",
afl->orig_cmdline);
/* ignore errors */
if (afl->debug) {
uint32_t i = 0;
u32 i = 0;
fprintf(f, "virgin_bytes :");
for (i = 0; i < afl->fsrv.map_size; i++) {
@ -206,7 +255,8 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
afl->plot_prev_qc == afl->queue_cycle &&
afl->plot_prev_uc == afl->unique_crashes &&
afl->plot_prev_uh == afl->unique_hangs &&
afl->plot_prev_md == afl->max_depth) ||
afl->plot_prev_md == afl->max_depth &&
afl->plot_prev_ed == afl->fsrv.total_execs) ||
unlikely(!afl->queue_cycle) ||
unlikely(get_cur_time() - afl->start_time <= 60)) {
@ -222,6 +272,7 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
afl->plot_prev_uc = afl->unique_crashes;
afl->plot_prev_uh = afl->unique_hangs;
afl->plot_prev_md = afl->max_depth;
afl->plot_prev_ed = afl->fsrv.total_execs;
/* Fields in the file:
@ -229,12 +280,13 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
favored_not_fuzzed, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
execs_per_sec */
fprintf(afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n",
get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
eps); /* ignore errors */
fprintf(
afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu\n",
get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
afl->plot_prev_ed); /* ignore errors */
fflush(afl->fsrv.plot_file);

View File

@ -173,10 +173,14 @@ static void usage(u8 *argv0, int more_help) {
"AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
"AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n"
" then they are randomly selected instead all of them being\n"
" 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_CPU_RED: avoid red color for showing very high cpu usage\n"
@ -188,7 +192,7 @@ static void usage(u8 *argv0, int more_help) {
"AFL_QUIET: suppress forkserver status messages\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
"AFL_SKIP_BIN_CHECK: skip the check, if the target is an excutable\n"
"AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n"
"AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
"AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
@ -949,8 +953,36 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->afl_env.afl_hang_tmout) {
afl->hang_tmout = atoi(afl->afl_env.afl_hang_tmout);
if (!afl->hang_tmout) { FATAL("Invalid value of AFL_HANG_TMOUT"); }
s32 hang_tmout = atoi(afl->afl_env.afl_hang_tmout);
if (hang_tmout < 1) { FATAL("Invalid value for AFL_HANG_TMOUT"); }
afl->hang_tmout = (u32)hang_tmout;
}
if (afl->afl_env.afl_max_det_extras) {
s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
if (max_det_extras < 1) { FATAL("Invalid value for AFL_MAX_DET_EXTRAS"); }
afl->max_det_extras = (u32)max_det_extras;
} else {
afl->max_det_extras = MAX_DET_EXTRAS;
}
if (afl->afl_env.afl_forksrv_init_tmout) {
afl->fsrv.init_tmout = atoi(afl->afl_env.afl_forksrv_init_tmout);
if (!afl->fsrv.init_tmout) {
FATAL("Invalid value of AFL_FORKSRV_INIT_TMOUT");
}
} else {
afl->fsrv.init_tmout = afl->fsrv.exec_tmout * FORK_WAIT_MULT;
}
@ -1096,6 +1128,8 @@ int main(int argc, char **argv_orig, char **envp) {
setup_custom_mutators(afl);
write_setup_file(afl, argc, argv);
setup_cmdline_file(afl, argv + optind);
read_testcases(afl);

View File

@ -415,7 +415,7 @@ int main(int argc, char **argv) {
"AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n"
"AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n";
if (argc == 2 && strcmp(argv[1], "-h") == 0) {
if (argc == 2 && strncmp(argv[1], "-h", 2) == 0) {
printf("afl-cc" VERSION " by Michal Zalewski\n\n");
printf("%s \n\n", argv[0]);

View File

@ -22,7 +22,10 @@
#include <stdint.h>
#include "afl-fuzz.h"
#include "types.h"
#include "xxh3.h"
#define XXH_INLINE_ALL
#include "xxhash.h"
#undef XXH_INLINE_ALL
/* we use xoshiro256** instead of rand/random because it is 10x faster and has
better randomness properties. */
@ -72,12 +75,12 @@ void jump(afl_state_t *afl) {
static const uint64_t JUMP[] = {0x180ec6d33cfd0aba, 0xd5a61266f0c9392c,
0xa9582618e03fc9aa, 0x39abdc4529b1661c};
int i, b;
size_t i, b;
uint64_t s0 = 0;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
for (i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
for (i = 0; i < (sizeof(JUMP) / sizeof(*JUMP)); i++)
for (b = 0; b < 64; b++) {
if (JUMP[i] & UINT64_C(1) << b) {
@ -110,12 +113,12 @@ void long_jump(afl_state_t *afl) {
static const uint64_t LONG_JUMP[] = {0x76e15d3efefdcbbf, 0xc5004e441c522fb3,
0x77710069854ee241, 0x39109bb02acbe635};
int i, b;
size_t i, b;
uint64_t s0 = 0;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
for (i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
for (i = 0; i < (sizeof(LONG_JUMP) / sizeof(*LONG_JUMP)); i++)
for (b = 0; b < 64; b++) {
if (LONG_JUMP[i] & UINT64_C(1) << b) {
@ -145,7 +148,7 @@ void long_jump(afl_state_t *afl) {
u32 hash32(u8 *key, u32 len, u32 seed) {
#else
u32 inline hash32(u8 *key, u32 len, u32 seed) {
inline u32 hash32(u8 *key, u32 len, u32 seed) {
#endif
@ -157,7 +160,7 @@ u32 inline hash32(u8 *key, u32 len, u32 seed) {
u64 hash64(u8 *key, u32 len, u64 seed) {
#else
u64 inline hash64(u8 *key, u32 len, u64 seed) {
inline u64 hash64(u8 *key, u32 len, u64 seed) {
#endif

View File

@ -636,6 +636,8 @@ static void usage(u8 *argv0) {
"size\n"
" the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during "
"startup (in milliseconds)\n"
"AFL_QUIET: do not print extra informational output\n",
argv0, MEM_LIMIT, doc_path);
@ -1036,6 +1038,19 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
if (forksrv_init_tmout < 1) {
FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
}
fsrv->init_tmout = (u32)forksrv_init_tmout;
}
afl_fsrv_start(fsrv, use_argv, &stop_soon,
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
map_size = fsrv->map_size;

View File

@ -846,6 +846,7 @@ static void usage(u8 *argv0) {
" 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"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
@ -1104,6 +1105,19 @@ int main(int argc, char **argv_orig, char **envp) {
SAYF("\n");
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
if (forksrv_init_tmout < 1) {
FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
}
fsrv->init_tmout = (u32)forksrv_init_tmout;
}
shm_fuzz = ck_alloc(sizeof(sharedmem_t));
/* initialize cmplog_mode */

View File

@ -42,7 +42,24 @@ int __wrap_printf(const char *format, ...) {
return 1;
}
#define BUF_PARAMS (void **)&buf, &size
#define VOID_BUF (void **)&buf
static void *create_fake_maybe_grow_of(size_t size) {
size += AFL_ALLOC_SIZE_OFFSET;
// fake a realloc buf
struct afl_alloc_buf *buf = malloc(size);
if (!buf) {
perror("Could not allocate fake buf");
return NULL;
}
buf->complete_size = size; // The size
void *actual_buf = (void *)(buf->buf);
return actual_buf;
}
/*
static int setup(void **state) {
@ -52,29 +69,55 @@ static int setup(void **state) {
}
*/
static void test_pow2(void **state) {
(void)state;
assert_int_equal(next_pow2(64), 64);
assert_int_equal(next_pow2(63), 64);
assert_int_not_equal(next_pow2(65), 65);
assert_int_equal(next_pow2(0x100), 0x100);
assert_int_equal(next_pow2(0x180), 0x200);
assert_int_equal(next_pow2(108), 0x80);
assert_int_equal(next_pow2(0), 0);
assert_int_equal(next_pow2(1), 1);
assert_int_equal(next_pow2(2), 2);
assert_int_equal(next_pow2(3), 4);
assert_int_equal(next_pow2(0xFFFFFF), 0x1000000);
assert_int_equal(next_pow2(0xFFFFFFF), 0x10000000);
assert_int_equal(next_pow2(0xFFFFFF0), 0x10000000);
assert_int_equal(next_pow2(SIZE_MAX), 0);
assert_int_equal(next_pow2(-1), 0);
assert_int_equal(next_pow2(-2), 0);
}
static void test_null_allocs(void **state) {
(void)state;
void *buf = NULL;
size_t size = 0;
void *ptr = ck_maybe_grow(BUF_PARAMS, 100);
void *ptr = afl_realloc(VOID_BUF, 100);
if (unlikely(!buf)) { PFATAL("alloc"); }
size_t size = afl_alloc_bufsize(buf);
assert_true(buf == ptr);
assert_true(size >= 100);
ck_free(ptr);
afl_free(ptr);
}
static void test_nonpow2_size(void **state) {
(void)state;
char *buf = ck_alloc(150);
size_t size = 150;
char *buf = create_fake_maybe_grow_of(150);
buf[140] = '5';
char *ptr = ck_maybe_grow(BUF_PARAMS, 160);
char *ptr = afl_realloc(VOID_BUF, 160);
if (unlikely(!ptr)) { PFATAL("alloc"); }
size_t size = afl_alloc_bufsize(buf);
assert_ptr_equal(buf, ptr);
assert_true(size >= 160);
assert_true(buf[140] == '5');
ck_free(ptr);
afl_free(ptr);
}
@ -83,32 +126,37 @@ static void test_zero_size(void **state) {
char *buf = NULL;
size_t size = 0;
assert_non_null(maybe_grow(BUF_PARAMS, 0));
free(buf);
char *new_buf = afl_realloc(VOID_BUF, 0);
assert_non_null(new_buf);
assert_ptr_equal(buf, new_buf);
afl_free(buf);
buf = NULL;
size = 0;
char *ptr = ck_maybe_grow(BUF_PARAMS, 100);
char *ptr = afl_realloc(VOID_BUF, 100);
if (unlikely(!ptr)) { PFATAL("alloc"); }
size = afl_alloc_bufsize(buf);
assert_non_null(ptr);
assert_ptr_equal(buf, ptr);
assert_true(size >= 100);
expect_assert_failure(ck_maybe_grow(BUF_PARAMS, 0));
ck_free(ptr);
afl_free(ptr);
}
static void test_unchanged_size(void **state) {
(void)state;
void *buf = ck_alloc(100);
size_t size = 100;
void *buf_before = buf;
void *buf_after = ck_maybe_grow(BUF_PARAMS, 100);
assert_ptr_equal(buf, buf_after);
// fake a realloc buf
void *actual_buf = create_fake_maybe_grow_of(100);
void *buf_before = actual_buf;
void *buf_after = afl_realloc(&actual_buf, 100);
if (unlikely(!buf_after)) { PFATAL("alloc"); }
assert_ptr_equal(actual_buf, buf_after);
assert_ptr_equal(buf_after, buf_before);
ck_free(buf);
afl_free(buf_after);
}
@ -118,29 +166,35 @@ static void test_grow_multiple(void **state) {
char *buf = NULL;
size_t size = 0;
char *ptr = ck_maybe_grow(BUF_PARAMS, 100);
char *ptr = afl_realloc(VOID_BUF, 100);
if (unlikely(!ptr)) { PFATAL("alloc"); }
size = afl_alloc_bufsize(ptr);
assert_ptr_equal(ptr, buf);
assert_true(size >= 100);
assert_int_equal(size, next_pow2(size));
assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
buf[50] = '5';
ptr = (char *)ck_maybe_grow(BUF_PARAMS, 1000);
ptr = (char *)afl_realloc(VOID_BUF, 1000);
if (unlikely(!ptr)) { PFATAL("alloc"); }
size = afl_alloc_bufsize(ptr);
assert_ptr_equal(ptr, buf);
assert_true(size >= 100);
assert_int_equal(size, next_pow2(size));
assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
buf[500] = '5';
ptr = (char *)ck_maybe_grow(BUF_PARAMS, 10000);
ptr = (char *)afl_realloc(VOID_BUF, 10000);
if (unlikely(!ptr)) { PFATAL("alloc"); }
size = afl_alloc_bufsize(ptr);
assert_ptr_equal(ptr, buf);
assert_true(size >= 10000);
assert_int_equal(size, next_pow2(size));
assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET);
buf[5000] = '5';
assert_int_equal(buf[50], '5');
assert_int_equal(buf[500], '5');
assert_int_equal(buf[5000], '5');
ck_free(buf);
afl_free(buf);
}
@ -157,6 +211,7 @@ int main(int argc, char **argv) {
(void)argv;
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_pow2),
cmocka_unit_test(test_null_allocs),
cmocka_unit_test(test_nonpow2_size),
cmocka_unit_test(test_zero_size),

View File

@ -70,6 +70,11 @@ MAKECMD=make
TARCMD=tar
if [ "$PLT" = "Linux" ]; then
MUSL=`ldd --version 2>&1 | head -n 1 | cut -f 1 -d " "`
if [ "musl" = $MUSL ]; then
echo "[-] Error: Unicorn instrumentation is unsupported with the musl's libc."
exit 1
fi
CORES=`nproc`
fi