mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
150 Commits
Author | SHA1 | Date | |
---|---|---|---|
ee206da389 | |||
fac108476c | |||
4f7a8a4c70 | |||
976ee9022c | |||
0625eb0a05 | |||
77b824d101 | |||
b7b38205d8 | |||
6c715f1a69 | |||
fc19aa96f7 | |||
50f61b64b1 | |||
809a7cffe2 | |||
6399f84ba2 | |||
8459bcdf85 | |||
6adaacbb3a | |||
6c846bcf2c | |||
e45ae8e5da | |||
cea2fadbf4 | |||
4c48d3a3ad | |||
020b8a4964 | |||
08f6e1d66a | |||
28e457e8d8 | |||
c7255f2e26 | |||
6340674a23 | |||
4538f689ed | |||
e4a86b40a5 | |||
75c38d6243 | |||
6f75100602 | |||
07cee6b750 | |||
651ad18e21 | |||
664daa2f3c | |||
ed6243df5a | |||
bd57784664 | |||
7f621509ee | |||
4261e17b3e | |||
8ca4414d70 | |||
6090bb1bca | |||
a552631d3b | |||
c552229c4d | |||
2dffed1cff | |||
e93f78eca5 | |||
9bbbec3fa8 | |||
338638b124 | |||
17e1a72b3b | |||
3e6471b949 | |||
e4de4e3500 | |||
bea76b346c | |||
53e63e9ded | |||
b1b5e21600 | |||
d765740707 | |||
192cadee34 | |||
d7d8afa512 | |||
01fcee1190 | |||
0805437222 | |||
4398b9b517 | |||
909262f6c5 | |||
155ef8875a | |||
58cf030546 | |||
18ea9a8447 | |||
ebd1e6bc4b | |||
45d866d548 | |||
8087cf7988 | |||
9e8b3f13e1 | |||
ce4700ca6e | |||
8253f90134 | |||
86421f3469 | |||
811ef13b20 | |||
7fb72f1038 | |||
d2c9e4baa7 | |||
81767287c3 | |||
6c980e2a02 | |||
e7db4d4fe0 | |||
567042d146 | |||
4697e4a5a5 | |||
92b1f9cf36 | |||
bbf00204ea | |||
a42b74b624 | |||
7ee255cbcf | |||
961ddfd7f8 | |||
4566bcf122 | |||
ca0105ddf6 | |||
41bb359428 | |||
146ede0f29 | |||
c0fd7ba6d1 | |||
b0b2a15891 | |||
ff3c9cbd73 | |||
6e839f0f6a | |||
a3cd523250 | |||
b44620f0b0 | |||
9a6a32775f | |||
3e8beaafc8 | |||
33e58c1d4e | |||
4be0ea596b | |||
96ef7083c8 | |||
78eaa6b203 | |||
1efc6e59b7 | |||
19eddbb0c7 | |||
6a34c5aa3e | |||
c7f0d30668 | |||
a7c3f252d5 | |||
b9b6f06429 | |||
a1442bd1ac | |||
4d9d52e3d9 | |||
6184832ea9 | |||
e2b54bfa05 | |||
425908a00c | |||
1301552101 | |||
c4f71ab201 | |||
42ef1968a5 | |||
5ec91fce23 | |||
47878f6974 | |||
d5c77a9e96 | |||
4d2694c114 | |||
017c8a6940 | |||
b0a783e86f | |||
714e4d2b46 | |||
85a4c5e724 | |||
182b8b3e14 | |||
4ce5ed370a | |||
f7bac482e9 | |||
bd074e9150 | |||
d52ea44c27 | |||
9c1b6cfb99 | |||
631d3f274a | |||
3cdaf4dcf2 | |||
572944d726 | |||
779d8f6b7e | |||
322847755a | |||
f9f28b9c7c | |||
c3bc0145e7 | |||
17d403b8f8 | |||
9faf7b6fc8 | |||
5c759953f4 | |||
1c64048d0f | |||
b504b9313a | |||
1a94cfe2af | |||
7470b475a9 | |||
0a6084f361 | |||
f92607cff1 | |||
9532499ef5 | |||
1d56de6c1d | |||
266b51a842 | |||
cc1fe2f2d2 | |||
43214d6b46 | |||
2f28ecd3a5 | |||
73a629d6f2 | |||
0a251f93e0 | |||
1cf4738487 | |||
af14acf2c1 | |||
8044ae28be | |||
6b1ad311da |
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
6
.gitmodules
vendored
@ -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
|
||||
|
@ -4,8 +4,9 @@ sudo: required
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- stable
|
||||
- dev
|
||||
- llvm_merge
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
85
GNUmakefile
85
GNUmakefile
@ -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
|
||||
@ -521,10 +528,9 @@ clean:
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
test -d qemu_taint/qemu && { cd qemu_taint ; ./clean.sh ; }
|
||||
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
|
||||
@ -532,7 +538,6 @@ endif
|
||||
|
||||
deepclean: clean
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf qemu_taint/qemu
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
git reset --hard >/dev/null 2>&1 || true
|
||||
|
||||
@ -568,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/^\.\///' >> $@
|
||||
@ -590,7 +596,6 @@ install: all $(MANPAGES)
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-qemu-taint ]; then install -m 755 afl-qemu-taint $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@ -600,6 +605,8 @@ install: all $(MANPAGES)
|
||||
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
|
||||
if [ -f libAFLDriver.a ]; then install -m 644 libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libAFLQemuDriver.a ]; then install -m 644 libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
|
||||
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
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
|
||||
|
54
README.md
54
README.md
@ -1,45 +1,12 @@
|
||||
# qemu_taint variant.
|
||||
|
||||
UPDATE: **WORKS NOW** **PLEASE TEST** **:-)**
|
||||
|
||||
## HOWTO
|
||||
|
||||
cd qemu_taint && ./build_qemu_taint.sh
|
||||
|
||||
afl-fuzz -A ...
|
||||
|
||||
## CAVEATS
|
||||
|
||||
* llvm shmem persistent mode does not and can not not work
|
||||
* MOpt works but totally ignores the taint information, so disabled here
|
||||
* custom mutators? dunno if they work or not. depends on how they work.
|
||||
* not tested with qemu_mode
|
||||
* there are several debug checks to ensure the data is fine which slows down
|
||||
fuzzing, if the beta experiment runs fine these will be improved and it
|
||||
will result in quite a speed gain.
|
||||
|
||||
## THE TAINT
|
||||
|
||||
taint can be seen in out/taint/
|
||||
|
||||
the id:000 mirrors the out/queue entry, except the content it 0x00 for
|
||||
untainted bytes and '!' for tainted bytes.
|
||||
If a file has new tainted bytes compared to from which previous entry it
|
||||
was created then there is a id:000[...].new file where the new bytes are
|
||||
marked '!'.
|
||||
|
||||
the mutation switches between fuzzing all tainted bytes in one cycle and
|
||||
only new bytes in the other cycle.
|
||||
|
||||
# American Fuzzy Lop plus plus (afl++)
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
||||

|
||||
|
||||
Release Version: [2.66c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release Version: [2.68c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 2.66d
|
||||
Github Version: 3.00a
|
||||
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
@ -52,7 +19,7 @@ only new bytes in the other cycle.
|
||||
|
||||
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
|
||||
@ -108,7 +75,7 @@ only new bytes in the other cycle.
|
||||
* 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.
|
||||
|
||||
@ -128,7 +95,7 @@ only new bytes in the other cycle.
|
||||
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
|
||||
@ -243,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".
|
||||
@ -351,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
|
||||
@ -612,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
|
||||
@ -694,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:
|
||||
@ -717,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
|
||||
@ -1068,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
12
TODO.md
@ -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 :-(
|
||||
|
1
afl-cmin
1
afl-cmin
@ -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
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
191
afl_driver.cpp
191
afl_driver.cpp
@ -1,191 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Platform detection. Copied from FuzzerInternal.h
|
||||
#ifdef __linux__
|
||||
#define LIBFUZZER_LINUX 1
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __APPLE__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 1
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __NetBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 1
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __FreeBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 1
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __OpenBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 1
|
||||
#else
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
static volatile char suppress_warning2 = AFL_PERSISTENT[0];
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
|
||||
|
||||
// Input buffer.
|
||||
static const size_t kMaxAflInputSize = 1024000;
|
||||
static uint8_t AflInputBuf[kMaxAflInputSize];
|
||||
|
||||
// Use this optionally defined function to output sanitizer messages even if
|
||||
// user asks to close stderr.
|
||||
__attribute__((weak)) void __sanitizer_set_report_fd(void *);
|
||||
|
||||
// Keep track of where stderr content is being written to, so that
|
||||
// dup_and_close_stderr can use the correct one.
|
||||
static FILE *output_file = stderr;
|
||||
|
||||
// Experimental feature to use afl_driver without AFL's deferred mode.
|
||||
// Needs to run before __afl_auto_init.
|
||||
__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
|
||||
if (getenv("AFL_DRIVER_DONT_DEFER")) {
|
||||
if (unsetenv("__AFL_DEFER_FORKSRV")) {
|
||||
perror("Failed to unset __AFL_DEFER_FORKSRV");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user asks us to duplicate stderr, then do it.
|
||||
static void maybe_duplicate_stderr() {
|
||||
char *stderr_duplicate_filename =
|
||||
getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
|
||||
if (!stderr_duplicate_filename)
|
||||
return;
|
||||
|
||||
FILE *stderr_duplicate_stream =
|
||||
freopen(stderr_duplicate_filename, "a+", stderr);
|
||||
|
||||
if (!stderr_duplicate_stream) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
abort();
|
||||
}
|
||||
output_file = stderr_duplicate_stream;
|
||||
}
|
||||
|
||||
// Most of these I/O functions were inspired by/copied from libFuzzer's code.
|
||||
static void discard_output(int fd) {
|
||||
FILE *temp = fopen("/dev/null", "w");
|
||||
if (!temp)
|
||||
abort();
|
||||
dup2(fileno(temp), fd);
|
||||
fclose(temp);
|
||||
}
|
||||
|
||||
static void close_stdout() { discard_output(STDOUT_FILENO); }
|
||||
|
||||
// Prevent the targeted code from writing to "stderr" but allow sanitizers and
|
||||
// this driver to do so.
|
||||
static void dup_and_close_stderr() {
|
||||
int output_fileno = fileno(output_file);
|
||||
int output_fd = dup(output_fileno);
|
||||
if (output_fd <= 0)
|
||||
abort();
|
||||
FILE *new_output_file = fdopen(output_fd, "w");
|
||||
if (!new_output_file)
|
||||
abort();
|
||||
if (!__sanitizer_set_report_fd)
|
||||
return;
|
||||
__sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
|
||||
discard_output(output_fileno);
|
||||
}
|
||||
|
||||
// Close stdout and/or stderr if user asks for it.
|
||||
static void maybe_close_fd_mask() {
|
||||
char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
|
||||
if (!fd_mask_str)
|
||||
return;
|
||||
int fd_mask = atoi(fd_mask_str);
|
||||
if (fd_mask & 2)
|
||||
dup_and_close_stderr();
|
||||
if (fd_mask & 1)
|
||||
close_stdout();
|
||||
}
|
||||
|
||||
// Define LLVMFuzzerMutate to avoid link failures for targets that use it
|
||||
// with libFuzzer's LLVMFuzzerCustomMutator.
|
||||
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
printf(
|
||||
"======================= INFO =========================\n"
|
||||
"This binary is built for AFL-fuzz.\n"
|
||||
"To run the target function on individual input(s) execute this:\n"
|
||||
" %s < INPUT_FILE\n"
|
||||
"To fuzz with afl-fuzz execute this:\n"
|
||||
" afl-fuzz [afl-flags] %s [-N]\n"
|
||||
"afl-fuzz will run N iterations before "
|
||||
"re-spawning the process (default: 1000)\n"
|
||||
"======================================================\n",
|
||||
argv[0], argv[0]);
|
||||
|
||||
maybe_duplicate_stderr();
|
||||
maybe_close_fd_mask();
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
int N = 100000;
|
||||
if (argc == 2 && argv[1][0] == '-')
|
||||
N = atoi(argv[1] + 1);
|
||||
else if(argc == 2 && (N = atoi(argv[1])) > 0)
|
||||
printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
// on the first execution of LLVMFuzzerTestOneInput is ignored.
|
||||
uint8_t dummy_input[1] = {0};
|
||||
LLVMFuzzerTestOneInput(dummy_input, 1);
|
||||
|
||||
while (__afl_persistent_loop(N)) {
|
||||
ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
|
||||
if (n_read > 0) {
|
||||
LLVMFuzzerTestOneInput(AflInputBuf, n_read);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: successfully executed input(s)\n", argv[0]);
|
||||
}
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -9,9 +9,39 @@ 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.66d (devel)
|
||||
### 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
|
||||
- Due to the instrumentation needing more memory, the initial memory sizes
|
||||
for -m have been increased
|
||||
- afl-fuzz:
|
||||
- added -F option to allow -M main fuzzers to sync to foreign fuzzers,
|
||||
e.g. honggfuzz or libfuzzer
|
||||
@ -20,12 +50,13 @@ 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!
|
||||
- now supports llvm 12
|
||||
- support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous
|
||||
AFL_LLVM_WHITELIST and AFL_LLVM_INSTRUMENT_FILE are deprecated and
|
||||
are matched to AFL_LLVM_ALLOWLIST). The format is compatible to llvm
|
||||
sancov, and also supports function matching!
|
||||
sancov, and also supports function matching :)
|
||||
- added neverzero counting to trace-pc/pcgard
|
||||
- fixes for laf-intel float splitting (thanks to mark-griffin for
|
||||
reporting)
|
||||
@ -33,9 +64,12 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- skipping ctors and ifuncs for instrumentation
|
||||
- LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR
|
||||
for a fixed map address (eg. 0x10000)
|
||||
- LTO: improved stability for persistent mode, no other instrumentation
|
||||
has that advantage
|
||||
- LTO: fixed autodict for long strings
|
||||
- LTO: laf-intel and redqueen/cmplog are now applied at link time
|
||||
to prevent llvm optimizing away the splits
|
||||
- LTO: autodictionary mode is a default
|
||||
- LTO: autodictionary mode is a fixed default now
|
||||
- LTO: instrim instrumentation disabled, only classic support used
|
||||
as it is always better
|
||||
- LTO: env var AFL_LLVM_DOCUMENT_IDS=file will document which edge ID
|
||||
@ -391,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
|
||||
|
130
docs/FAQ.md
130
docs/FAQ.md
@ -2,44 +2,68 @@
|
||||
|
||||
## Contents
|
||||
|
||||
1. [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
|
||||
2. [How do I fuzz a network service?](#how-to-fuzz-a-network-service)
|
||||
3. [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program)
|
||||
4. [What is an edge?](#what-is-an-edge)
|
||||
5. [Why is my stability below 100%?](#why-is-my-stability-below-100)
|
||||
6. [How can I improve the stability value](#how-can-i-improve-the-stability-value)
|
||||
* [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-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)
|
||||
|
||||
If you find an interesting or important question missing, submit it via
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues)
|
||||
|
||||
## How to improve the fuzzing speed
|
||||
## What is the difference between afl and afl++?
|
||||
|
||||
1. use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended)
|
||||
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 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 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 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?
|
||||
|
||||
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) -
|
||||
@ -50,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
|
||||
@ -59,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:
|
||||
@ -75,7 +99,7 @@ function() {
|
||||
if (x) goto C; else goto D;
|
||||
C:
|
||||
some code
|
||||
goto D
|
||||
goto E
|
||||
D:
|
||||
some code
|
||||
goto B
|
||||
@ -85,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
|
||||
@ -100,31 +124,48 @@ 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
|
||||
path through the target every time. If that is the case, the stability is 100%.
|
||||
|
||||
If however randomness happens, e.g. a thread reading from shared memory,
|
||||
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
|
||||
will result in the edge information being 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?
|
||||
|
||||
Four steps are required to do this and requires quite some knowledge of
|
||||
coding and/or disassembly and it is only effectively possible with
|
||||
afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
|
||||
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
|
||||
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 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 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 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
|
||||
|
||||
@ -132,12 +173,12 @@ 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/afile`.
|
||||
This file will have one assigned edge ID and the corresponding function
|
||||
per line.
|
||||
time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`.
|
||||
This file will have one assigned edge ID and the corresponding
|
||||
function per line.
|
||||
|
||||
b) For PCGUARD instrumented binaries it is much more difficult. Here you
|
||||
can either modify the __sanitizer_cov_trace_pc_guard function in
|
||||
@ -151,16 +192,29 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation!
|
||||
on start, check to which memory address the edge ID value is written
|
||||
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 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 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
|
||||
should not put the function in a deny instrumentation list and rather
|
||||
live with the instability it comes with.
|
||||
|
||||
4. Fourth step: recompile the target
|
||||
|
||||
Recompile, fuzz it, be happy :)
|
||||
|
||||
This link explains this process for [Fuzzbench](https://github.com/google/fuzzbench/issues/677)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -16,6 +16,7 @@ aflpp_driver.o: aflpp_driver.c
|
||||
|
||||
libAFLDriver.a: aflpp_driver.o
|
||||
ar ru libAFLDriver.a aflpp_driver.o
|
||||
cp -vf libAFLDriver.a ../../
|
||||
|
||||
debug:
|
||||
$(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
|
||||
@ -29,6 +30,7 @@ aflpp_qemu_driver.o: aflpp_qemu_driver.c
|
||||
|
||||
libAFLQemuDriver.a: aflpp_qemu_driver.o
|
||||
ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
cp -vf libAFLQemuDriver.a ../../
|
||||
|
||||
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
|
||||
$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so
|
||||
|
@ -106,7 +106,9 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both.
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
int __afl_sharedmem_fuzzing = 0;
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int * __afl_fuzz_len;
|
||||
extern unsigned char *__afl_fuzz_ptr;
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
@ -272,7 +274,6 @@ int main(int argc, char **argv) {
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
uint8_t dummy_input[64] = {0};
|
||||
uint8_t buf[1024000];
|
||||
memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
|
||||
memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
|
||||
sizeof(AFL_DEFER_FORKSVR));
|
||||
@ -283,24 +284,16 @@ int main(int argc, char **argv) {
|
||||
printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
|
||||
else if (argc > 1) {
|
||||
|
||||
if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
|
||||
|
||||
__afl_manual_init();
|
||||
|
||||
}
|
||||
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
__afl_manual_init();
|
||||
return ExecuteFilesOnyByOne(argc, argv);
|
||||
|
||||
}
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
|
||||
|
||||
fprintf(stderr, "performing manual init\n");
|
||||
__afl_manual_init();
|
||||
|
||||
}
|
||||
// if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
// on the first execution of LLVMFuzzerTestOneInput is ignored.
|
||||
@ -309,13 +302,25 @@ int main(int argc, char **argv) {
|
||||
int num_runs = 0;
|
||||
while (__afl_persistent_loop(N)) {
|
||||
|
||||
ssize_t r = read(0, buf, sizeof(buf));
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "CLIENT crc: %016llx len: %u\n",
|
||||
hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705),
|
||||
*__afl_fuzz_len);
|
||||
fprintf(stderr, "RECV:");
|
||||
for (int i = 0; i < *__afl_fuzz_len; i++)
|
||||
fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (*__afl_fuzz_len) {
|
||||
|
||||
if (r > 0) { LLVMFuzzerTestOneInput(buf, r); }
|
||||
num_runs++;
|
||||
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf("%s: successfully executed input(s)\n", argv[0]);
|
||||
printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -133,10 +136,8 @@ extern s32
|
||||
|
||||
struct queue_entry {
|
||||
|
||||
u8 * fname; /* File name for the test case */
|
||||
u8 * fname_taint; /* File name for taint data */
|
||||
u32 len; /* Input length */
|
||||
struct queue_entry *prev; /* previous queue entry, if any */
|
||||
u8 *fname; /* File name for the test case */
|
||||
u32 len; /* Input length */
|
||||
|
||||
u8 cal_failed, /* Calibration failed? */
|
||||
trim_done, /* Trimmed? */
|
||||
@ -150,10 +151,7 @@ struct queue_entry {
|
||||
is_ascii; /* Is the input just ascii text? */
|
||||
|
||||
u32 bitmap_size, /* Number of bits set in bitmap */
|
||||
fuzz_level, /* Number of fuzzing iterations */
|
||||
taint_bytes_all, /* Number of tainted bytes */
|
||||
taint_bytes_new, /* Number of new tainted bytes */
|
||||
taint_bytes_highest; /* highest offset in input */
|
||||
fuzz_level; /* Number of fuzzing iterations */
|
||||
|
||||
u64 exec_us, /* Execution time (us) */
|
||||
handicap, /* Number of queue cycles behind */
|
||||
@ -290,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
|
||||
|
||||
};
|
||||
@ -355,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;
|
||||
|
||||
@ -385,8 +387,6 @@ typedef struct afl_state {
|
||||
|
||||
char **argv; /* argv if needed */
|
||||
|
||||
char **argv_taint; /* argv for taint mode */
|
||||
|
||||
/* MOpt:
|
||||
Lots of globals, but mostly for the status UI and other things where it
|
||||
really makes no sense to haul them around as function parameters. */
|
||||
@ -438,9 +438,7 @@ typedef struct afl_state {
|
||||
*in_bitmap, /* Input bitmap */
|
||||
*file_extension, /* File extension */
|
||||
*orig_cmdline, /* Original command line */
|
||||
*infoexec, /* Command to execute on a new crash */
|
||||
*taint_input_file, /* fuzz_input_one input file */
|
||||
*taint_src, *taint_map;
|
||||
*infoexec; /* Command to execute on a new crash */
|
||||
|
||||
u32 hang_tmout; /* Timeout used for hang det (ms) */
|
||||
|
||||
@ -451,9 +449,7 @@ typedef struct afl_state {
|
||||
custom_only, /* Custom mutator only mode */
|
||||
python_only, /* Python-only mode */
|
||||
is_main_node, /* if this is the main node */
|
||||
is_secondary_node, /* if this is a secondary instance */
|
||||
taint_needs_splode, /* explode fuzz input */
|
||||
taint_mode;
|
||||
is_secondary_node; /* if this is a secondary instance */
|
||||
|
||||
u32 stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
@ -515,7 +511,7 @@ typedef struct afl_state {
|
||||
var_byte_count, /* Bitmap bytes with var behavior */
|
||||
current_entry, /* Current queue entry ID */
|
||||
havoc_div, /* Cycle count divisor for havoc */
|
||||
taint_len, taint_count;
|
||||
max_det_extras; /* deterministic extra count (dicts)*/
|
||||
|
||||
u64 total_crashes, /* Total number of crashes */
|
||||
unique_crashes, /* Crashes with unique signatures */
|
||||
@ -584,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 */
|
||||
|
||||
@ -602,9 +597,6 @@ typedef struct afl_state {
|
||||
char * cmplog_binary;
|
||||
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
|
||||
|
||||
/* Taint mode */
|
||||
afl_forkserver_t taint_fsrv; /* taint mode has its own little forkserver */
|
||||
|
||||
/* Custom mutators */
|
||||
struct custom_mutator *mutator;
|
||||
|
||||
@ -637,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;
|
||||
@ -648,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;
|
||||
|
||||
@ -681,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 */
|
||||
@ -697,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
|
||||
*
|
||||
@ -856,8 +859,7 @@ struct custom_mutator {
|
||||
|
||||
};
|
||||
|
||||
void afl_state_init_1(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_init_2(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_init(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_deinit(afl_state_t *);
|
||||
|
||||
/* Set stop_soon flag on all childs, kill all childs */
|
||||
@ -886,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);
|
||||
@ -903,7 +906,7 @@ void deinit_py(void *);
|
||||
void mark_as_det_done(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_variable(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_redundant(afl_state_t *, struct queue_entry *, u8);
|
||||
void add_to_queue(afl_state_t *, u8 *, u8 *, u32, struct queue_entry *, u8);
|
||||
void add_to_queue(afl_state_t *, u8 *, u32, u8);
|
||||
void destroy_queue(afl_state_t *);
|
||||
void update_bitmap_score(afl_state_t *, struct queue_entry *);
|
||||
void cull_queue(afl_state_t *);
|
||||
@ -913,9 +916,7 @@ u32 calculate_score(afl_state_t *, struct queue_entry *);
|
||||
|
||||
void write_bitmap(afl_state_t *);
|
||||
u32 count_bits(afl_state_t *, u8 *);
|
||||
u32 count_bits_len(afl_state_t *, u8 *, u32);
|
||||
u32 count_bytes(afl_state_t *, u8 *);
|
||||
u32 count_bytes_len(afl_state_t *, u8 *, u32);
|
||||
u32 count_non_255_bytes(afl_state_t *, u8 *);
|
||||
#ifdef WORD_SIZE_64
|
||||
void simplify_trace(afl_state_t *, u64 *);
|
||||
@ -936,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 *);
|
||||
@ -943,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 *);
|
||||
@ -993,8 +996,6 @@ void check_if_tty(afl_state_t *);
|
||||
void setup_signal_handlers(void);
|
||||
void save_cmdline(afl_state_t *, u32, char **);
|
||||
void read_foreign_testcases(afl_state_t *, int);
|
||||
void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname,
|
||||
u8 *mem, u32 len);
|
||||
|
||||
/* CmpLog */
|
||||
|
||||
@ -1027,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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ extern u8 *doc_path; /* path to documentation dir */
|
||||
@returns the path, allocating the string */
|
||||
|
||||
u8 *find_binary(u8 *fname);
|
||||
u8 *find_afl_binary(u8 *fname, u8 *own_loc);
|
||||
|
||||
/* Read a bitmap from file fname to memory
|
||||
This is for the -B option again. */
|
||||
@ -111,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
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++2.66d"
|
||||
#define VERSION "++2.68c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -70,21 +70,21 @@
|
||||
|
||||
#ifndef __NetBSD__
|
||||
#ifndef WORD_SIZE_64
|
||||
#define MEM_LIMIT 25
|
||||
#else
|
||||
#define MEM_LIMIT 50
|
||||
#else
|
||||
#define MEM_LIMIT 75
|
||||
#endif /* ^!WORD_SIZE_64 */
|
||||
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
|
||||
#165 */
|
||||
#define MEM_LIMIT 200
|
||||
#define MEM_LIMIT 250
|
||||
#endif
|
||||
/* Default memory limit when running in QEMU mode (MB): */
|
||||
|
||||
#define MEM_LIMIT_QEMU 200
|
||||
#define MEM_LIMIT_QEMU 250
|
||||
|
||||
/* Default memory limit when running in Unicorn mode (MB): */
|
||||
|
||||
#define MEM_LIMIT_UNICORN 200
|
||||
#define MEM_LIMIT_UNICORN 250
|
||||
|
||||
/* Number of calibration cycles per every new test case (and for test
|
||||
cases that show variable behavior): */
|
||||
|
@ -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",
|
||||
@ -123,7 +129,6 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_SKIP_BIN_CHECK",
|
||||
"AFL_SKIP_CPUFREQ",
|
||||
"AFL_SKIP_CRASHES",
|
||||
"AFL_TAINT_INPUT",
|
||||
"AFL_TMIN_EXACT",
|
||||
"AFL_TMPDIR",
|
||||
"AFL_TOKEN_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) */
|
||||
@ -80,8 +81,6 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 qemu_mode; /* if running in qemu mode or not */
|
||||
|
||||
u8 taint_mode; /* if running taint analysis or not */
|
||||
|
||||
u32 *shmem_fuzz_len; /* length of the fuzzing test case */
|
||||
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
@ -93,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;
|
||||
|
||||
|
3187
include/xxh3.h
3187
include/xxh3.h
File diff suppressed because it is too large
Load Diff
3763
include/xxhash.h
3763
include/xxhash.h
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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/^\.\///' >> ../$@
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
1503
llvm_mode/SanitizerCoverageLTO.so.cc
Normal file
1503
llvm_mode/SanitizerCoverageLTO.so.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
@ -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()) {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
@ -103,6 +103,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
std::vector<std::string> dictionary;
|
||||
std::vector<CallInst *> calls;
|
||||
DenseMap<Value *, std::string *> valueMap;
|
||||
std::vector<BasicBlock *> BlockList;
|
||||
char * ptr;
|
||||
FILE * documentFile = NULL;
|
||||
|
||||
@ -134,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;
|
||||
@ -290,14 +287,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
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;
|
||||
bool isStrcmp = true;
|
||||
bool isMemcmp = true;
|
||||
bool isStrncmp = true;
|
||||
bool isStrcasecmp = true;
|
||||
bool isStrncasecmp = true;
|
||||
bool isIntMemcpy = true;
|
||||
bool addedNull = false;
|
||||
size_t optLen = 0;
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
@ -310,6 +307,24 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
isStrncasecmp &= !FuncName.compare("strncasecmp");
|
||||
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
|
||||
|
||||
/* we do something different here, putting this BB and the
|
||||
successors in a block map */
|
||||
if (!FuncName.compare("__afl_persistent_loop")) {
|
||||
|
||||
BlockList.push_back(&BB);
|
||||
/*
|
||||
for (succ_iterator SI = succ_begin(&BB), SE =
|
||||
succ_end(&BB); SI != SE; ++SI) {
|
||||
|
||||
BasicBlock *succ = *SI;
|
||||
BlockList.push_back(succ);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
|
||||
!isStrncasecmp && !isIntMemcpy)
|
||||
continue;
|
||||
@ -359,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(),
|
||||
@ -527,18 +555,27 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
// add null byte if this is a string compare function and a null
|
||||
// was not already added
|
||||
if (addedNull == false && !isMemcmp) {
|
||||
if (!isMemcmp) {
|
||||
|
||||
thestring.append("\0", 1); // add null byte
|
||||
optLen++;
|
||||
if (addedNull == false) {
|
||||
|
||||
thestring.append("\0", 1); // add null byte
|
||||
optLen++;
|
||||
|
||||
}
|
||||
|
||||
// ensure we do not have garbage
|
||||
size_t offset = thestring.find('\0', 0);
|
||||
if (offset + 1 < optLen) optLen = offset + 1;
|
||||
thestring = thestring.substr(0, optLen);
|
||||
|
||||
}
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
std::string outstring;
|
||||
fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
|
||||
(unsigned int)thestring.length());
|
||||
fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
|
||||
thestring.length());
|
||||
for (uint8_t i = 0; i < thestring.length(); i++) {
|
||||
|
||||
uint8_t c = thestring[i];
|
||||
@ -574,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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -107,6 +107,10 @@ struct cmp_map *__afl_cmp_map;
|
||||
|
||||
static u8 is_persistent;
|
||||
|
||||
/* Are we in sancov mode? */
|
||||
|
||||
static u8 _is_sancov;
|
||||
|
||||
/* Error reporting to forkserver controller */
|
||||
|
||||
void send_forkserver_error(int error) {
|
||||
@ -190,19 +194,10 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
if (__afl_area_ptr && __afl_final_loc &&
|
||||
__afl_final_loc > MAP_INITIAL_SIZE &&
|
||||
__afl_area_ptr != __afl_area_initial) {
|
||||
|
||||
munmap(__afl_area_ptr, __afl_final_loc);
|
||||
__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_final_loc % 8)
|
||||
__afl_final_loc = (((__afl_final_loc + 7) >> 3) << 3);
|
||||
|
||||
__afl_map_size = __afl_final_loc;
|
||||
|
||||
if (__afl_final_loc > MAP_SIZE) {
|
||||
|
||||
char *ptr;
|
||||
@ -212,10 +207,12 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_final_loc);
|
||||
if (!getenv("AFL_QUIET"))
|
||||
fprintf(stderr,
|
||||
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u "
|
||||
"to be able to run this instrumented program!\n",
|
||||
__afl_final_loc);
|
||||
|
||||
if (id_str) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
@ -225,10 +222,11 @@ static void __afl_map_shm(void) {
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr,
|
||||
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_final_loc);
|
||||
if (!getenv("AFL_QUIET"))
|
||||
fprintf(stderr,
|
||||
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u "
|
||||
"to be able to run this instrumented program!\n",
|
||||
__afl_final_loc);
|
||||
|
||||
}
|
||||
|
||||
@ -244,13 +242,25 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
fprintf(stderr,
|
||||
"DEBUG: id_str %s, __afl_map_addr 0x%llx, MAP_SIZE %u, "
|
||||
"__afl_final_loc %u, max_size_forkserver %u/0x%x\n",
|
||||
id_str == NULL ? "<null>" : id_str, __afl_map_addr, MAP_SIZE,
|
||||
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
|
||||
"DEBUG: id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
|
||||
"__afl_map_addr 0x%llx, MAP_SIZE %u, __afl_final_loc %u, "
|
||||
"max_size_forkserver %u/0x%x\n",
|
||||
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
|
||||
__afl_area_initial, __afl_map_addr, MAP_SIZE, __afl_final_loc,
|
||||
FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
|
||||
|
||||
if (id_str) {
|
||||
|
||||
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) {
|
||||
|
||||
if (__afl_map_addr)
|
||||
munmap((void *)__afl_map_addr, __afl_final_loc);
|
||||
else
|
||||
free(__afl_area_ptr);
|
||||
__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
}
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
@ -319,19 +329,30 @@ static void __afl_map_shm(void) {
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
|
||||
} else if (__afl_map_addr) {
|
||||
} else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
|
||||
|
||||
__afl_map_addr) {
|
||||
|
||||
__afl_area_ptr =
|
||||
mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
} else if (_is_sancov && __afl_area_ptr != __afl_area_initial) {
|
||||
|
||||
free(__afl_area_ptr);
|
||||
__afl_area_ptr = NULL;
|
||||
if (__afl_final_loc > MAP_INITIAL_SIZE)
|
||||
__afl_area_ptr = malloc(__afl_final_loc);
|
||||
if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
|
||||
|
||||
}
|
||||
|
||||
id_str = getenv(CMPLOG_SHM_ENV_VAR);
|
||||
@ -888,29 +909,50 @@ __attribute__((constructor())) void __afl_auto_init(void) {
|
||||
|
||||
__attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
|
||||
is_persistent = !!getenv(PERSIST_ENV_VAR);
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
|
||||
__afl_map_shm();
|
||||
|
||||
}
|
||||
|
||||
/* preset __afl_area_ptr */
|
||||
/* preset __afl_area_ptr #2 */
|
||||
|
||||
__attribute__((constructor(1))) void __afl_auto_second(void) {
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr;
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial)
|
||||
free(__afl_area_ptr);
|
||||
|
||||
if (__afl_map_addr)
|
||||
ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_final_loc,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
else
|
||||
ptr = (u8 *)malloc(__afl_final_loc);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* preset __afl_area_ptr #1 - at constructor level 0 global variables have
|
||||
not been set */
|
||||
|
||||
__attribute__((constructor(0))) void __afl_auto_first(void) {
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr;
|
||||
|
||||
if (__afl_final_loc > MAP_INITIAL_SIZE) {
|
||||
ptr = (u8 *)malloc(1024000);
|
||||
|
||||
ptr = (u8 *)mmap(NULL, __afl_final_loc, PROT_READ | PROT_WRITE, MAP_PRIVATE,
|
||||
-1, 0);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) { __afl_area_ptr = ptr; }
|
||||
|
||||
}
|
||||
if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
|
||||
|
||||
}
|
||||
|
||||
@ -978,6 +1020,8 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
u32 inst_ratio = 100;
|
||||
char *x;
|
||||
|
||||
_is_sancov = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
# qemu_taint
|
||||
|
||||
First level taint implementation with qemu for linux user mode
|
||||
|
||||
**THIS IS NOT WORKING YET** **WIP**
|
||||
|
||||
## What is this for
|
||||
|
||||
On new queue entries (newly discovered paths into the target) this tainter
|
||||
is run with the new input and the data gathered which bytes in the input
|
||||
file are actually touched.
|
||||
|
||||
Only touched bytes are then fuzzed by afl-fuzz
|
||||
|
||||
## How to build
|
||||
|
||||
./build_qemu_taint.sh
|
||||
|
||||
## How to use
|
||||
|
||||
Add the -A flag to afl-fuzz
|
||||
|
||||
## Caveats
|
||||
|
||||
For some targets this is amazing and improves fuzzing a lot, but if a target
|
||||
copies all input bytes first (e.g. for creating a crc checksum or just to
|
||||
safely work with the data), then this is not helping at all.
|
||||
|
||||
## Future
|
||||
|
||||
Two fuzz modes for a queue entry which will be switched back and forth:
|
||||
|
||||
1. fuzz all touched bytes
|
||||
2. fuzz only bytes that are newly touched (compared to the one this queue
|
||||
entry is based on)
|
||||
|
||||
## TODO
|
||||
|
||||
* Direct trim: trim to highest touched byte, that is all we need to do
|
||||
* add 5-25% dummy bytes to the queue entries? (maybe create a 2nd one?)
|
||||
* Disable trim?
|
||||
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1
|
||||
cd qemu || exit 1
|
||||
test -d .git && { git stash ; git pull ; }
|
||||
cp -fv ../../include/config.h ../../include/types.h . || exit 1
|
||||
./build.sh || exit 1
|
||||
cp -fv ./afl-qemu-taint ../..
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
rm -f afl-qemu-taint qemu/afl-qemu-taint ../afl-qemu-taint
|
||||
test -d qemu && { cd qemu ; ./clean.sh ; }
|
@ -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;
|
||||
|
204
src/afl-common.c
204
src/afl-common.c
@ -138,59 +138,12 @@ void argv_cpy_free(char **argv) {
|
||||
|
||||
}
|
||||
|
||||
u8 *find_afl_binary(u8 *fname, u8 *own_loc) {
|
||||
|
||||
u8 *tmp, *rsl, *own_copy, *cp;
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/%s", tmp, fname);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
return cp;
|
||||
|
||||
}
|
||||
|
||||
if (own_loc) {
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/%s", own_copy, fname);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) { return cp; }
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cp = alloc_printf("%s/%s", BIN_PATH, fname);
|
||||
if (!access(cp, X_OK)) { return cp; }
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Rewrite argv for QEMU. */
|
||||
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
|
||||
u8 * cp = NULL;
|
||||
u8 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
@ -200,15 +153,51 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
cp = find_afl_binary("afl-qemu-trace", own_loc);
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (cp) {
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
|
||||
|
||||
if (cp) { ck_free(cp); }
|
||||
*target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
|
||||
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
|
||||
"built\n"
|
||||
@ -236,7 +225,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 3));
|
||||
u8 * cp = NULL;
|
||||
u8 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
@ -245,16 +234,66 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
cp = find_afl_binary("afl-qemu-trace", own_loc);
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (cp) {
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
ck_free(cp);
|
||||
cp = find_afl_binary("afl-wine-trace", own_loc);
|
||||
|
||||
if (cp) {
|
||||
cp = alloc_printf("%s/afl-wine-trace", tmp);
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
|
||||
if (cp && !access(cp, X_OK)) {
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
cp = alloc_printf("%s/afl-wine-trace", own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
u8 *ncp = BIN_PATH "/afl-qemu-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
ncp = BIN_PATH "/afl-wine-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = ck_strdup(ncp);
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
@ -262,21 +301,25 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the afl-qemu-trace and afl-wine-trace binaries.\n"
|
||||
"The afl-qemu-trace binary must be built separately by following the "
|
||||
"instructions\n"
|
||||
"in qemu_mode/README.md. If you already have the binary installed, you "
|
||||
"may need\n"
|
||||
"to specify the location via AFL_PATH in the environment.\n\n"
|
||||
"Oops, unable to find the '%s' binary. The binary must be "
|
||||
"built\n"
|
||||
" separately by following the instructions in "
|
||||
"qemu_mode/README.md. "
|
||||
"If you\n"
|
||||
" already have the binary installed, you may need to specify "
|
||||
"AFL_PATH in the\n"
|
||||
" environment.\n\n"
|
||||
|
||||
" Of course, even without QEMU, afl-fuzz can still work with "
|
||||
"binaries that are\n"
|
||||
" instrumented at compile time with afl-gcc. It is also possible to "
|
||||
"use it as a\n"
|
||||
" traditional non-instrumented fuzzer by specifying '-n' in the "
|
||||
"command "
|
||||
"line.\n");
|
||||
"line.\n",
|
||||
ncp);
|
||||
|
||||
FATAL("Failed to locate 'afl-qemu-trace' and 'afl-wine-trace'.");
|
||||
FATAL("Failed to locate '%s'.", ncp);
|
||||
|
||||
}
|
||||
|
||||
@ -834,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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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(). */
|
||||
@ -498,21 +528,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
char pid_buf[16];
|
||||
sprintf(pid_buf, "%d", fsrv->fsrv_pid);
|
||||
|
||||
if (fsrv->taint_mode) {
|
||||
|
||||
setenv("__AFL_TARGET_PID3", pid_buf, 1);
|
||||
|
||||
} else if (fsrv->cmplog_binary) {
|
||||
|
||||
if (fsrv->cmplog_binary)
|
||||
setenv("__AFL_TARGET_PID2", pid_buf, 1);
|
||||
|
||||
} else {
|
||||
|
||||
else
|
||||
setenv("__AFL_TARGET_PID1", pid_buf, 1);
|
||||
|
||||
}
|
||||
|
||||
/* Close the unneeded endpoints. */
|
||||
|
||||
close(ctl_pipe[0]);
|
||||
@ -526,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);
|
||||
@ -640,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);
|
||||
@ -725,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++;
|
||||
|
||||
@ -947,9 +966,9 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
|
||||
|
||||
} else {
|
||||
|
||||
s32 fd;
|
||||
s32 fd = fsrv->out_fd;
|
||||
|
||||
if (fsrv->out_file) {
|
||||
if (!fsrv->use_stdin) {
|
||||
|
||||
if (fsrv->no_unlink) {
|
||||
|
||||
@ -966,14 +985,13 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
|
||||
|
||||
} else {
|
||||
|
||||
fd = fsrv->out_fd;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -177,40 +177,6 @@ u32 count_bits(afl_state_t *afl, u8 *mem) {
|
||||
|
||||
}
|
||||
|
||||
u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
u32 *ptr = (u32 *)mem;
|
||||
u32 i = (len >> 2);
|
||||
u32 ret = 0;
|
||||
|
||||
(void)(afl);
|
||||
|
||||
if (len % 4) i++;
|
||||
|
||||
while (i--) {
|
||||
|
||||
u32 v = *(ptr++);
|
||||
|
||||
/* This gets called on the inverse, virgin bitmap; optimize for sparse
|
||||
data. */
|
||||
|
||||
if (v == 0xffffffff) {
|
||||
|
||||
ret += 32;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
v -= ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Count the number of bytes set in the bitmap. Called fairly sporadically,
|
||||
mostly to update the status screen or calibrate and examine confirmed
|
||||
new paths. */
|
||||
@ -237,32 +203,6 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) {
|
||||
|
||||
}
|
||||
|
||||
u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
u32 *ptr = (u32 *)mem;
|
||||
u32 i = (len >> 2);
|
||||
u32 ret = 0;
|
||||
|
||||
(void)(afl);
|
||||
|
||||
if (len % 4) i++;
|
||||
|
||||
while (i--) {
|
||||
|
||||
u32 v = *(ptr++);
|
||||
|
||||
if (!v) { continue; }
|
||||
if (v & 0x000000ff) { ++ret; }
|
||||
if (v & 0x0000ff00) { ++ret; }
|
||||
if (v & 0x00ff0000) { ++ret; }
|
||||
if (v & 0xff000000) { ++ret; }
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Count the number of non-255 bytes set in the bitmap. Used strictly for the
|
||||
status screen, several calls per second or so. */
|
||||
|
||||
@ -655,7 +595,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
#endif /* ^!SIMPLE_FILES */
|
||||
|
||||
add_to_queue(afl, queue_fn, mem, len, afl->queue_top, 0);
|
||||
add_to_queue(afl, queue_fn, len, 0);
|
||||
|
||||
if (hnb == 2) {
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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__)
|
||||
@ -712,7 +712,7 @@ void read_testcases(afl_state_t *afl) {
|
||||
|
||||
if (!access(dfn, F_OK)) { passed_det = 1; }
|
||||
|
||||
add_to_queue(afl, fn2, NULL, st.st_size, NULL, passed_det);
|
||||
add_to_queue(afl, fn2, st.st_size, passed_det);
|
||||
|
||||
}
|
||||
|
||||
@ -771,13 +771,9 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
close(fd);
|
||||
|
||||
res = calibrate_case(afl, q, use_mem, 0, 1);
|
||||
ck_free(use_mem);
|
||||
|
||||
if (afl->stop_soon) {
|
||||
|
||||
ck_free(use_mem);
|
||||
return;
|
||||
|
||||
}
|
||||
if (afl->stop_soon) { return; }
|
||||
|
||||
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
|
||||
|
||||
@ -964,10 +960,6 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
/* perform taint gathering on the input seed */
|
||||
if (afl->taint_mode) perform_taint_run(afl, q, q->fname, use_mem, q->len);
|
||||
ck_free(use_mem);
|
||||
|
||||
q = q->next;
|
||||
|
||||
}
|
||||
@ -1446,10 +1438,6 @@ static void handle_existing_out_dir(afl_state_t *afl) {
|
||||
|
||||
u8 *orig_q = alloc_printf("%s/queue", afl->out_dir);
|
||||
|
||||
u8 *fnt = alloc_printf("%s/taint", afl->out_dir);
|
||||
mkdir(fnt, 0755); // ignore errors
|
||||
ck_free(fnt);
|
||||
|
||||
afl->in_dir = alloc_printf("%s/_resume", afl->out_dir);
|
||||
|
||||
rename(orig_q, afl->in_dir); /* Ignore errors */
|
||||
@ -1506,20 +1494,6 @@ static void handle_existing_out_dir(afl_state_t *afl) {
|
||||
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
fn = alloc_printf("%s/taint", afl->out_dir);
|
||||
mkdir(fn, 0755); // ignore errors
|
||||
|
||||
u8 *fn2 = alloc_printf("%s/taint/.input", afl->out_dir);
|
||||
unlink(fn2); // ignore errors
|
||||
ck_free(fn2);
|
||||
|
||||
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
|
||||
}
|
||||
|
||||
/* All right, let's do <afl->out_dir>/crashes/id:* and
|
||||
* <afl->out_dir>/hangs/id:*. */
|
||||
|
||||
@ -1747,16 +1721,6 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Taint directory if taint_mode. */
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
tmp = alloc_printf("%s/taint", afl->out_dir);
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
}
|
||||
|
||||
/* Top-level directory for queue metadata used for session
|
||||
resume and related tasks. */
|
||||
|
||||
@ -1877,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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -95,7 +95,7 @@ static u32 choose_block_len(afl_state_t *afl, u32 limit) {
|
||||
|
||||
default:
|
||||
|
||||
if (rand_below(afl, 10)) {
|
||||
if (likely(rand_below(afl, 10))) {
|
||||
|
||||
min_value = HAVOC_BLK_MEDIUM;
|
||||
max_value = HAVOC_BLK_LARGE;
|
||||
@ -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
|
||||
@ -421,7 +416,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
if (((afl->queue_cur->was_fuzzed > 0 || afl->queue_cur->fuzz_level > 0) ||
|
||||
!afl->queue_cur->favored) &&
|
||||
rand_below(afl, 100) < SKIP_TO_NEW_PROB) {
|
||||
likely(rand_below(afl, 100) < SKIP_TO_NEW_PROB)) {
|
||||
|
||||
return 1;
|
||||
|
||||
@ -438,11 +433,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
if (afl->queue_cycle > 1 &&
|
||||
(afl->queue_cur->fuzz_level == 0 || afl->queue_cur->was_fuzzed)) {
|
||||
|
||||
if (rand_below(afl, 100) < SKIP_NFAV_NEW_PROB) { return 1; }
|
||||
if (likely(rand_below(afl, 100) < SKIP_NFAV_NEW_PROB)) { return 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (rand_below(afl, 100) < SKIP_NFAV_OLD_PROB) { return 1; }
|
||||
if (likely(rand_below(afl, 100) < SKIP_NFAV_OLD_PROB)) { return 1; }
|
||||
|
||||
}
|
||||
|
||||
@ -458,176 +453,34 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
u32 tmp_val = 0;
|
||||
/* Map the test case into memory. */
|
||||
|
||||
if (unlikely(afl->taint_mode)) {
|
||||
fd = open(afl->queue_cur->fname, O_RDONLY);
|
||||
|
||||
tmp_val = afl->queue_cycle % 2; // starts with 1
|
||||
ret_val = 0;
|
||||
if (unlikely(fd < 0)) {
|
||||
|
||||
if (unlikely(afl->queue_cur->cal_failed && !tmp_val)) goto abandon_entry;
|
||||
if (unlikely(!afl->skip_deterministic && !afl->queue_cur->passed_det &&
|
||||
!tmp_val))
|
||||
goto abandon_entry;
|
||||
if ((!afl->queue_cur->taint_bytes_new ||
|
||||
afl->queue_cur->taint_bytes_new == afl->queue_cur->len) &&
|
||||
!tmp_val)
|
||||
goto abandon_entry;
|
||||
|
||||
ret_val = 1;
|
||||
|
||||
s32 dst = 0, i;
|
||||
temp_len = len = afl->queue_cur->len;
|
||||
s32 j = 0; // tmp
|
||||
|
||||
fd = open(afl->queue_cur->fname, O_RDONLY);
|
||||
afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)afl->taint_src == -1)
|
||||
FATAL("unable to open '%s'", afl->queue_cur->fname);
|
||||
close(fd);
|
||||
afl->taint_needs_splode = 1;
|
||||
|
||||
switch (tmp_val) {
|
||||
|
||||
case 1: // fuzz only tainted bytes
|
||||
|
||||
// special case: all or nothing tainted. in this case we act like
|
||||
// nothing is special. this is not the taint you are looking for ...
|
||||
if (!afl->queue_cur->taint_bytes_all ||
|
||||
afl->queue_cur->taint_bytes_all == (u32)len) {
|
||||
|
||||
orig_in = in_buf = afl->taint_src;
|
||||
afl->taint_needs_splode = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
fd = open(afl->taint_input_file, O_RDONLY);
|
||||
temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_all;
|
||||
orig_in = in_buf =
|
||||
mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->taint_input_file);
|
||||
close(fd);
|
||||
|
||||
fd = open(afl->queue_cur->fname_taint, O_RDONLY);
|
||||
afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->queue_cur->fname_taint);
|
||||
close(fd);
|
||||
|
||||
for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++)
|
||||
if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
|
||||
|
||||
// FIXME DEBUG TODO XXX
|
||||
for (i = 0; i < (s32)afl->queue_cur->len; i++) {
|
||||
|
||||
switch (afl->taint_map[i]) {
|
||||
|
||||
case 0x0:
|
||||
break;
|
||||
case '!':
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
FATAL(
|
||||
"invalid taint map entry byte 0x%02x at position %d "
|
||||
"(passed_det:%d)\n",
|
||||
afl->taint_map[i], i, afl->queue_cur->passed_det);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (j != len)
|
||||
FATAL("different taint values in map vs in queue (%d != %d)", j, len);
|
||||
|
||||
break;
|
||||
|
||||
case 0: // fuzz only newly tainted bytes
|
||||
|
||||
fd = open(afl->taint_input_file, O_RDONLY);
|
||||
temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_new;
|
||||
orig_in = in_buf =
|
||||
mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->taint_input_file);
|
||||
close(fd);
|
||||
|
||||
u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint);
|
||||
if (!fn) FATAL("OOM");
|
||||
fd = open(fn, O_RDWR);
|
||||
afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s' for %u bytes", fn, len);
|
||||
close(fd);
|
||||
ck_free(fn);
|
||||
|
||||
for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++)
|
||||
if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
|
||||
|
||||
// FIXME DEBUG TODO XXX
|
||||
for (i = 0; i < (s32)afl->queue_cur->len; i++) {
|
||||
|
||||
switch (afl->taint_map[i]) {
|
||||
|
||||
case 0x0:
|
||||
break;
|
||||
case '!':
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
FATAL(
|
||||
"invalid taint map entry byte 0x%02x at position %d "
|
||||
"(passed_det:%d)\n",
|
||||
afl->taint_map[i], i, afl->queue_cur->passed_det);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (j != len)
|
||||
FATAL("different taint values in map vs in queue (%d != %d)", j, len);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Map the test case into memory. */
|
||||
|
||||
fd = open(afl->queue_cur->fname, O_RDONLY);
|
||||
|
||||
if (unlikely(fd < 0)) {
|
||||
|
||||
PFATAL("Unable to open '%s'", afl->queue_cur->fname);
|
||||
|
||||
}
|
||||
|
||||
len = afl->queue_cur->len;
|
||||
|
||||
orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
|
||||
if (unlikely(orig_in == MAP_FAILED)) {
|
||||
|
||||
PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
PFATAL("Unable to open '%s'", afl->queue_cur->fname);
|
||||
|
||||
}
|
||||
|
||||
len = afl->queue_cur->len;
|
||||
|
||||
orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
|
||||
if (unlikely(orig_in == MAP_FAILED)) {
|
||||
|
||||
PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every
|
||||
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;
|
||||
|
||||
@ -645,12 +498,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
afl->queue_cur->exec_cksum = 0;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
res = calibrate_case(afl, afl->queue_cur, afl->taint_src,
|
||||
afl->queue_cycle - 1, 0);
|
||||
else
|
||||
res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1,
|
||||
0);
|
||||
res =
|
||||
calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
|
||||
|
||||
if (unlikely(res == FSRV_RUN_ERROR)) {
|
||||
|
||||
@ -674,7 +523,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
************/
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
|
||||
!afl->disable_trim && !afl->taint_needs_splode)) {
|
||||
!afl->disable_trim)) {
|
||||
|
||||
u8 res = trim_case(afl, afl->queue_cur, in_buf);
|
||||
|
||||
@ -709,28 +558,15 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(perf_score == 0)) { goto abandon_entry; }
|
||||
|
||||
if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
|
||||
if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) {
|
||||
|
||||
int res;
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
if (input_to_state_stage(afl, in_buf, out_buf, len,
|
||||
afl->queue_cur->exec_cksum)) {
|
||||
|
||||
len = afl->queue_cur->len;
|
||||
memcpy(out_buf, afl->taint_src, len);
|
||||
res = input_to_state_stage(afl, afl->taint_src, out_buf, len,
|
||||
afl->queue_cur->exec_cksum);
|
||||
// just abandon as success
|
||||
ret_val = 0;
|
||||
res = 1;
|
||||
|
||||
} else {
|
||||
|
||||
res = input_to_state_stage(afl, in_buf, out_buf, len,
|
||||
afl->queue_cur->exec_cksum);
|
||||
goto abandon_entry;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(res)) { goto abandon_entry; }
|
||||
|
||||
}
|
||||
|
||||
/* Skip right away if -d is given, if it has not been chosen sufficiently
|
||||
@ -751,8 +587,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
/* Skip deterministic fuzzing if exec path checksum puts this out of scope
|
||||
for this main instance. */
|
||||
|
||||
if (afl->main_node_max && (afl->queue_cur->exec_cksum % afl->main_node_max) !=
|
||||
afl->main_node_id - 1) {
|
||||
if (unlikely(afl->main_node_max &&
|
||||
(afl->queue_cur->exec_cksum % afl->main_node_max) !=
|
||||
afl->main_node_id - 1)) {
|
||||
|
||||
goto custom_mutator_stage;
|
||||
|
||||
@ -959,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) {
|
||||
@ -1671,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,
|
||||
@ -1716,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) {
|
||||
|
||||
@ -1833,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;
|
||||
|
||||
@ -1841,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2067,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);
|
||||
|
||||
}
|
||||
@ -2291,20 +2151,10 @@ havoc_stage:
|
||||
u32 clone_from, clone_to, clone_len;
|
||||
u8 *new_buf;
|
||||
|
||||
if (actually_clone) {
|
||||
if (likely(actually_clone)) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
clone_len = choose_block_len(afl, afl->queue_cur->len);
|
||||
clone_from =
|
||||
rand_below(afl, afl->queue_cur->len - clone_len + 1);
|
||||
|
||||
} else {
|
||||
|
||||
clone_len = choose_block_len(afl, temp_len);
|
||||
clone_from = rand_below(afl, temp_len - clone_len + 1);
|
||||
|
||||
}
|
||||
clone_len = choose_block_len(afl, temp_len);
|
||||
clone_from = rand_below(afl, temp_len - clone_len + 1);
|
||||
|
||||
} else {
|
||||
|
||||
@ -2316,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 */
|
||||
|
||||
@ -2324,13 +2175,9 @@ havoc_stage:
|
||||
|
||||
/* Inserted part */
|
||||
|
||||
if (actually_clone) {
|
||||
if (likely(actually_clone)) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
memcpy(new_buf + clone_to, afl->taint_src + clone_from,
|
||||
clone_len);
|
||||
else
|
||||
memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
|
||||
memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
|
||||
|
||||
} else {
|
||||
|
||||
@ -2342,10 +2189,10 @@ havoc_stage:
|
||||
}
|
||||
|
||||
/* Tail */
|
||||
memmove(new_buf + clone_to + clone_len, out_buf + clone_to,
|
||||
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;
|
||||
@ -2363,49 +2210,16 @@ havoc_stage:
|
||||
|
||||
if (temp_len < 2) { break; }
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
copy_len = choose_block_len(afl, temp_len - 1);
|
||||
|
||||
copy_len = choose_block_len(afl, afl->queue_cur->len - 1);
|
||||
copy_from = rand_below(afl, afl->queue_cur->len - copy_len + 1);
|
||||
copy_to = rand_below(afl, temp_len + 1);
|
||||
copy_from = rand_below(afl, temp_len - copy_len + 1);
|
||||
copy_to = rand_below(afl, temp_len - copy_len + 1);
|
||||
|
||||
} else {
|
||||
|
||||
copy_len = choose_block_len(afl, temp_len - 1);
|
||||
copy_from = rand_below(afl, temp_len - copy_len + 1);
|
||||
copy_to = rand_below(afl, temp_len - copy_len + 1);
|
||||
|
||||
}
|
||||
|
||||
if (rand_below(afl, 4)) {
|
||||
if (likely(rand_below(afl, 4))) {
|
||||
|
||||
if (copy_from != copy_to) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
if (temp_len >= (s32)(copy_to + copy_len)) {
|
||||
|
||||
memcpy(out_buf + copy_to, afl->taint_src + copy_from,
|
||||
copy_len);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch),
|
||||
copy_to + copy_len);
|
||||
memcpy(new_buf, in_buf, copy_to);
|
||||
memcpy(new_buf + copy_to, afl->taint_src + copy_from,
|
||||
copy_len);
|
||||
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
|
||||
out_buf = new_buf;
|
||||
temp_len = copy_to + copy_len;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
|
||||
|
||||
}
|
||||
memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
|
||||
|
||||
}
|
||||
|
||||
@ -2493,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,
|
||||
@ -2549,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);
|
||||
|
||||
@ -2589,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 */
|
||||
|
||||
@ -2603,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;
|
||||
|
||||
@ -2624,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);
|
||||
|
||||
@ -2671,17 +2489,10 @@ havoc_stage:
|
||||
splices them together at some offset, then relies on the havoc
|
||||
code to mutate that blob. */
|
||||
|
||||
u32 saved_len;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
saved_len = afl->taint_len;
|
||||
else
|
||||
saved_len = afl->queue_cur->len;
|
||||
|
||||
retry_splicing:
|
||||
|
||||
if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES &&
|
||||
afl->queued_paths > 1 && saved_len > 1) {
|
||||
afl->queued_paths > 1 && afl->queue_cur->len > 1) {
|
||||
|
||||
struct queue_entry *target;
|
||||
u32 tid, split_at;
|
||||
@ -2694,7 +2505,7 @@ retry_splicing:
|
||||
if (in_buf != orig_in) {
|
||||
|
||||
in_buf = orig_in;
|
||||
len = saved_len;
|
||||
len = afl->queue_cur->len;
|
||||
|
||||
}
|
||||
|
||||
@ -2726,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);
|
||||
|
||||
@ -2748,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;
|
||||
@ -2765,8 +2578,6 @@ retry_splicing:
|
||||
|
||||
ret_val = 0;
|
||||
|
||||
goto abandon_entry;
|
||||
|
||||
/* we are through with this queue entry - for this iteration */
|
||||
abandon_entry:
|
||||
|
||||
@ -2786,17 +2597,7 @@ abandon_entry:
|
||||
|
||||
++afl->queue_cur->fuzz_level;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
munmap(afl->taint_src, afl->queue_cur->len);
|
||||
munmap(orig_in, afl->taint_len);
|
||||
munmap(afl->taint_map, afl->queue_cur->len);
|
||||
|
||||
} else {
|
||||
|
||||
munmap(orig_in, afl->queue_cur->len);
|
||||
|
||||
}
|
||||
munmap(orig_in, afl->queue_cur->len);
|
||||
|
||||
return ret_val;
|
||||
|
||||
@ -2904,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;
|
||||
|
||||
@ -2979,7 +2781,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
|
||||
|
||||
orig_perf = perf_score = calculate_score(afl, afl->queue_cur);
|
||||
|
||||
if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
|
||||
if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) {
|
||||
|
||||
if (input_to_state_stage(afl, in_buf, out_buf, len,
|
||||
afl->queue_cur->exec_cksum)) {
|
||||
@ -3226,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) {
|
||||
@ -3938,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,
|
||||
@ -3983,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) {
|
||||
|
||||
@ -4421,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 */
|
||||
|
||||
@ -4448,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;
|
||||
@ -4565,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,
|
||||
@ -4598,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);
|
||||
|
||||
@ -4743,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);
|
||||
|
||||
@ -4770,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;
|
||||
@ -5105,5 +4914,3 @@ u8 fuzz_one(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
#undef BUF_PARAMS
|
||||
|
||||
|
@ -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"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
@ -103,169 +101,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
|
||||
|
||||
}
|
||||
|
||||
void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname,
|
||||
u8 *mem, u32 len) {
|
||||
|
||||
u8 * ptr, *fn = fname;
|
||||
u32 bytes = 0, plen = len;
|
||||
struct queue_entry *prev = q->prev;
|
||||
|
||||
if (plen % 4) plen = plen + 4 - (len % 4);
|
||||
|
||||
if ((ptr = strrchr(fname, '/')) != NULL) fn = ptr + 1;
|
||||
q->fname_taint = alloc_printf("%s/taint/%s", afl->out_dir, fn);
|
||||
|
||||
if (q->fname_taint) {
|
||||
|
||||
u8 *save = ck_maybe_grow(BUF_PARAMS(out_scratch), afl->fsrv.map_size);
|
||||
memcpy(save, afl->taint_fsrv.trace_bits, afl->fsrv.map_size);
|
||||
|
||||
afl->taint_fsrv.map_size = plen; // speed :)
|
||||
write_to_testcase(afl, mem, len);
|
||||
if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout * 4,
|
||||
&afl->stop_soon) == 0) {
|
||||
|
||||
bytes = q->taint_bytes_all =
|
||||
count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen);
|
||||
if (afl->debug)
|
||||
fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len);
|
||||
|
||||
/* DEBUG FIXME TODO XXX */
|
||||
u32 i;
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (afl->taint_fsrv.trace_bits[i] &&
|
||||
afl->taint_fsrv.trace_bits[i] != '!')
|
||||
FATAL("invalid taint map value %02x at pos %d",
|
||||
afl->taint_fsrv.trace_bits[i], i);
|
||||
|
||||
}
|
||||
|
||||
if (len < plen)
|
||||
for (i = len; i < plen; i++) {
|
||||
|
||||
if (afl->taint_fsrv.trace_bits[i])
|
||||
FATAL("invalid taint map value %02x in padding at pos %d",
|
||||
afl->taint_fsrv.trace_bits[i], i);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if all is tainted we do not need to write taint data away
|
||||
if (bytes && bytes < len) {
|
||||
|
||||
// save the bytes away
|
||||
int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644);
|
||||
if (w >= 0) {
|
||||
|
||||
ck_write(w, afl->taint_fsrv.trace_bits, len, q->fname_taint);
|
||||
close(w);
|
||||
|
||||
// find the highest tainted offset in the input (for trim opt)
|
||||
s32 i = len;
|
||||
while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1])
|
||||
i--;
|
||||
q->taint_bytes_highest = i;
|
||||
|
||||
afl->taint_count++;
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("could not create %s", q->fname_taint);
|
||||
q->taint_bytes_all = bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
// it is possible that there is no main taint file - if the whole file
|
||||
// is tainted - but a .new taint file if it had new tainted bytes
|
||||
|
||||
// check if there is a previous queue entry and if it had taint
|
||||
if (bytes && prev && prev->taint_bytes_all &&
|
||||
prev->taint_bytes_all < prev->len) {
|
||||
|
||||
// check if there are new bytes in the taint vs the previous
|
||||
int r = open(prev->fname_taint, O_RDONLY);
|
||||
|
||||
if (r >= 0) {
|
||||
|
||||
u8 *bufr = mmap(0, prev->len, PROT_READ, MAP_PRIVATE, r, 0);
|
||||
|
||||
if ((ssize_t)bufr != -1) {
|
||||
|
||||
u32 i;
|
||||
u8 *tmp = ck_maybe_grow(BUF_PARAMS(in_scratch), plen);
|
||||
memset(tmp, 0, plen);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (afl->taint_fsrv.trace_bits[i] && (i >= prev->len || !bufr[i]))
|
||||
tmp[i] = '!';
|
||||
|
||||
q->taint_bytes_new = count_bytes_len(afl, tmp, plen);
|
||||
|
||||
if (afl->debug)
|
||||
fprintf(stderr, "Debug: %u new taint out of %u bytes\n", bytes,
|
||||
len);
|
||||
|
||||
if (q->taint_bytes_new) {
|
||||
|
||||
u8 *fnw = alloc_printf("%s.new", q->fname_taint);
|
||||
if (fnw) {
|
||||
|
||||
int w = open(fnw, O_CREAT | O_WRONLY, 0644);
|
||||
if (w >= 0) {
|
||||
|
||||
ck_write(w, tmp, plen, fnw);
|
||||
close(w);
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("count not create '%s'", fnw);
|
||||
q->taint_bytes_new = 0;
|
||||
|
||||
}
|
||||
|
||||
ck_free(fnw);
|
||||
|
||||
} else {
|
||||
|
||||
q->taint_bytes_new = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
munmap(bufr, prev->len);
|
||||
|
||||
}
|
||||
|
||||
close(r);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
memcpy(afl->taint_fsrv.trace_bits, save, afl->fsrv.map_size);
|
||||
|
||||
}
|
||||
|
||||
if (!bytes) {
|
||||
|
||||
q->taint_bytes_highest = q->taint_bytes_all = q->taint_bytes_new = 0;
|
||||
|
||||
if (q->fname_taint) {
|
||||
|
||||
ck_free(q->fname_taint);
|
||||
q->fname_taint = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* check if ascii or UTF-8 */
|
||||
|
||||
static u8 check_if_text(struct queue_entry *q) {
|
||||
@ -303,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++;
|
||||
@ -375,12 +210,10 @@ static u8 check_if_text(struct queue_entry *q) {
|
||||
|
||||
/* Append new test case to the queue. */
|
||||
|
||||
void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
struct queue_entry *prev_q, u8 passed_det) {
|
||||
void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
|
||||
|
||||
q->prev = prev_q;
|
||||
q->fname = fname;
|
||||
q->len = len;
|
||||
q->depth = afl->cur_depth + 1;
|
||||
@ -413,19 +246,13 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/* trigger the tain gathering if this is not a dry run */
|
||||
if (afl->taint_mode && mem) { perform_taint_run(afl, q, fname, mem, len); }
|
||||
|
||||
/* only redqueen currently uses is_ascii */
|
||||
if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
|
||||
|
||||
/* run custom mutators afl_custom_queue_new_entry() */
|
||||
if (afl->custom_mutators_count) {
|
||||
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
@ -445,6 +272,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
|
||||
}
|
||||
|
||||
/* only redqueen currently uses is_ascii */
|
||||
if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
|
||||
|
||||
}
|
||||
|
||||
/* Destroy the entire queue. */
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
@ -350,9 +347,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->taint_mode))
|
||||
q->exec_cksum = 0;
|
||||
else if (q->exec_cksum) {
|
||||
if (q->exec_cksum) {
|
||||
|
||||
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
@ -755,65 +750,56 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
while (remove_pos < q->len) {
|
||||
|
||||
u32 trim_avail = MIN(remove_len, q->len - remove_pos);
|
||||
u64 cksum;
|
||||
|
||||
if (likely((!q->taint_bytes_highest) ||
|
||||
(q->len - trim_avail > q->taint_bytes_highest))) {
|
||||
write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
|
||||
|
||||
u64 cksum;
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
++afl->trim_execs;
|
||||
|
||||
write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
|
||||
if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
++afl->trim_execs;
|
||||
/* Note that we don't keep track of crashes or hangs here; maybe TODO?
|
||||
*/
|
||||
|
||||
if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
/* Note that we don't keep track of crashes or hangs here; maybe TODO?
|
||||
*/
|
||||
/* If the deletion had no impact on the trace, make it permanent. This
|
||||
isn't perfect for variable-path inputs, but we're just making a
|
||||
best-effort pass, so it's not a big deal if we end up with false
|
||||
negatives every now and then. */
|
||||
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
if (cksum == q->exec_cksum) {
|
||||
|
||||
/* If the deletion had no impact on the trace, make it permanent. This
|
||||
isn't perfect for variable-path inputs, but we're just making a
|
||||
best-effort pass, so it's not a big deal if we end up with false
|
||||
negatives every now and then. */
|
||||
u32 move_tail = q->len - remove_pos - trim_avail;
|
||||
|
||||
if (cksum == q->exec_cksum) {
|
||||
q->len -= trim_avail;
|
||||
len_p2 = next_pow2(q->len);
|
||||
|
||||
u32 move_tail = q->len - remove_pos - trim_avail;
|
||||
memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail,
|
||||
move_tail);
|
||||
|
||||
q->len -= trim_avail;
|
||||
len_p2 = next_pow2(q->len);
|
||||
/* Let's save a clean trace, which will be needed by
|
||||
update_bitmap_score once we're done with the trimming stuff. */
|
||||
|
||||
memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail,
|
||||
move_tail);
|
||||
if (!needs_write) {
|
||||
|
||||
/* Let's save a clean trace, which will be needed by
|
||||
update_bitmap_score once we're done with the trimming stuff. */
|
||||
|
||||
if (!needs_write) {
|
||||
|
||||
needs_write = 1;
|
||||
memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
remove_pos += remove_len;
|
||||
needs_write = 1;
|
||||
memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
|
||||
}
|
||||
|
||||
/* Since this can be slow, update the screen every now and then. */
|
||||
if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
|
||||
++afl->stage_cur;
|
||||
|
||||
} else {
|
||||
|
||||
remove_pos += remove_len;
|
||||
|
||||
}
|
||||
|
||||
/* Since this can be slow, update the screen every now and then. */
|
||||
|
||||
if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
|
||||
++afl->stage_cur;
|
||||
|
||||
}
|
||||
|
||||
remove_len >>= 1;
|
||||
@ -866,8 +852,6 @@ abort_trimming:
|
||||
|
||||
}
|
||||
|
||||
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
|
||||
|
||||
/* Write a modified test case, run program, process results. Handle
|
||||
error conditions, returning 1 if it's time to bail out. This is
|
||||
a helper function for fuzz_one(). */
|
||||
@ -877,32 +861,6 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
u8 fault;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
s32 new_len = afl->queue_cur->len + len - afl->taint_len;
|
||||
if (new_len < 4)
|
||||
new_len = 4;
|
||||
else if (new_len > MAX_FILE)
|
||||
new_len = MAX_FILE;
|
||||
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), new_len);
|
||||
|
||||
u32 i, taint = 0;
|
||||
for (i = 0; i < (u32)new_len; i++) {
|
||||
|
||||
if (i >= afl->taint_len || i >= afl->queue_cur->len || afl->taint_map[i])
|
||||
new_buf[i] = out_buf[taint++];
|
||||
else
|
||||
new_buf[i] = afl->taint_src[i];
|
||||
|
||||
}
|
||||
|
||||
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
|
||||
|
||||
out_buf = new_buf;
|
||||
len = new_len;
|
||||
|
||||
}
|
||||
|
||||
write_to_testcase(afl, out_buf, len);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
@ -950,5 +908,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
#undef BUF_PARAMS
|
||||
|
||||
|
@ -75,7 +75,7 @@ static list_t afl_states = {.element_prealloc_count = 0};
|
||||
|
||||
/* Initializes an afl_state_t. */
|
||||
|
||||
void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
/* thanks to this memset, growing vars like out_buf
|
||||
and out_size are NULL/0 by default. */
|
||||
@ -100,11 +100,21 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
afl->cpu_aff = -1; /* Selected CPU core */
|
||||
#endif /* HAVE_AFFINITY */
|
||||
|
||||
afl->virgin_bits = ck_alloc(map_size);
|
||||
afl->virgin_tmout = ck_alloc(map_size);
|
||||
afl->virgin_crash = ck_alloc(map_size);
|
||||
afl->var_bytes = ck_alloc(map_size);
|
||||
afl->top_rated = ck_alloc(map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_alloc(map_size);
|
||||
afl->clean_trace_custom = ck_alloc(map_size);
|
||||
afl->first_trace = ck_alloc(map_size);
|
||||
afl->map_tmp_buf = ck_alloc(map_size);
|
||||
|
||||
afl->fsrv.use_stdin = 1;
|
||||
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;
|
||||
@ -151,24 +161,6 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
}
|
||||
|
||||
void afl_state_init_2(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
afl->shm.map_size = map_size ? map_size : MAP_SIZE;
|
||||
|
||||
afl->virgin_bits = ck_alloc(map_size);
|
||||
afl->virgin_tmout = ck_alloc(map_size);
|
||||
afl->virgin_crash = ck_alloc(map_size);
|
||||
afl->var_bytes = ck_alloc(map_size);
|
||||
afl->top_rated = ck_alloc(map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_alloc(map_size);
|
||||
afl->clean_trace_custom = ck_alloc(map_size);
|
||||
afl->first_trace = ck_alloc(map_size);
|
||||
afl->map_tmp_buf = ck_alloc(map_size);
|
||||
|
||||
afl->fsrv.map_size = map_size;
|
||||
|
||||
}
|
||||
|
||||
/*This sets up the environment variables for afl-fuzz into the afl_state
|
||||
* struct*/
|
||||
|
||||
@ -357,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 {
|
||||
@ -429,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);
|
||||
|
@ -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. */
|
||||
@ -116,7 +164,6 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
||||
"edges_found : %u\n"
|
||||
"var_byte_count : %u\n"
|
||||
"havoc_expansion : %u\n"
|
||||
"tainted_inputs : %u\n"
|
||||
"afl_banner : %s\n"
|
||||
"afl_version : " VERSION
|
||||
"\n"
|
||||
@ -150,8 +197,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
||||
#else
|
||||
-1,
|
||||
#endif
|
||||
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->taint_count,
|
||||
afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
|
||||
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner,
|
||||
afl->unicorn_mode ? "unicorn" : "",
|
||||
afl->fsrv.qemu_mode ? "qemu " : "",
|
||||
afl->non_instrumented_mode ? " non_instrumented " : "",
|
||||
afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
|
||||
@ -164,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++) {
|
||||
|
||||
@ -207,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)) {
|
||||
|
||||
@ -223,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:
|
||||
|
||||
@ -230,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);
|
||||
|
||||
|
167
src/afl-fuzz.c
167
src/afl-fuzz.c
@ -53,9 +53,6 @@ static void at_exit() {
|
||||
ptr = getenv("__AFL_TARGET_PID2");
|
||||
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
|
||||
|
||||
ptr = getenv("__AFL_TARGET_PID3");
|
||||
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
|
||||
|
||||
i = 0;
|
||||
while (list[i] != NULL) {
|
||||
|
||||
@ -92,8 +89,6 @@ static void usage(u8 *argv0, int more_help) {
|
||||
" -o dir - output directory for fuzzer findings\n\n"
|
||||
|
||||
"Execution control settings:\n"
|
||||
" -A - use first level taint analysis (see "
|
||||
"qemu_taint/README.md)\n"
|
||||
" -p schedule - power schedules compute a seed's performance score. "
|
||||
"<explore\n"
|
||||
" (default), fast, coe, lin, quad, exploit, mmopt, "
|
||||
@ -178,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"
|
||||
@ -193,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"
|
||||
@ -244,10 +243,9 @@ static int stricmp(char const *a, char const *b) {
|
||||
|
||||
int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
s32 opt;
|
||||
u64 prev_queued = 0;
|
||||
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE,
|
||||
real_map_size = 0;
|
||||
s32 opt;
|
||||
u64 prev_queued = 0;
|
||||
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
|
||||
u8 * extras_dir = 0;
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0;
|
||||
char **use_argv;
|
||||
@ -263,7 +261,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; }
|
||||
|
||||
map_size = get_map_size();
|
||||
afl_state_init_1(afl, map_size);
|
||||
afl_state_init(afl, map_size);
|
||||
afl->debug = debug;
|
||||
afl_fsrv_init(&afl->fsrv);
|
||||
|
||||
@ -283,15 +281,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
while ((opt = getopt(
|
||||
argc, argv,
|
||||
"+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) {
|
||||
"+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'A':
|
||||
afl->taint_mode = 1;
|
||||
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
afl->infoexec = optarg;
|
||||
break;
|
||||
@ -499,7 +492,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (!optarg) { FATAL("Wrong usage of -m"); }
|
||||
|
||||
if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) {
|
||||
if (!strcmp(optarg, "none")) {
|
||||
|
||||
afl->fsrv.mem_limit = 0;
|
||||
break;
|
||||
@ -829,15 +822,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->taint_mode && afl->fsrv.map_size < MAX_FILE) {
|
||||
|
||||
real_map_size = map_size;
|
||||
map_size = MAX_FILE;
|
||||
|
||||
}
|
||||
|
||||
afl_state_init_2(afl, map_size);
|
||||
|
||||
if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
|
||||
|
||||
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
|
||||
@ -845,7 +829,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
OKF("afl++ is open source, get it at "
|
||||
"https://github.com/AFLplusplus/AFLplusplus");
|
||||
OKF("Power schedules from github.com/mboehme/aflfast");
|
||||
OKF("Python Mutator from github.com/choller/afl");
|
||||
OKF("Python Mutator and llvm_mode instrument file list from "
|
||||
"github.com/choller/afl");
|
||||
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
|
||||
|
||||
if (afl->sync_id && afl->is_main_node &&
|
||||
@ -891,19 +876,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
|
||||
if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
|
||||
if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
|
||||
if (afl->taint_mode) { FATAL("-A and -n are mutually exclusive"); }
|
||||
|
||||
}
|
||||
|
||||
if (afl->limit_time_sig != 0 && afl->taint_mode) {
|
||||
|
||||
FATAL("-A and -L are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
if (afl->unicorn_mode != 0 && afl->taint_mode) {
|
||||
|
||||
FATAL("-A and -U are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
@ -981,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;
|
||||
|
||||
}
|
||||
|
||||
@ -1004,7 +1004,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->afl_env.afl_preload) {
|
||||
|
||||
if (afl->fsrv.qemu_mode || afl->taint_mode) {
|
||||
if (afl->fsrv.qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
@ -1100,13 +1100,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
|
||||
|
||||
if (real_map_size && map_size != real_map_size) {
|
||||
|
||||
afl->fsrv.map_size = real_map_size;
|
||||
if (afl->cmplog_binary) afl->cmplog_fsrv.map_size = real_map_size;
|
||||
|
||||
}
|
||||
|
||||
if (!afl->in_bitmap) { memset(afl->virgin_bits, 255, afl->fsrv.map_size); }
|
||||
memset(afl->virgin_tmout, 255, afl->fsrv.map_size);
|
||||
memset(afl->virgin_crash, 255, afl->fsrv.map_size);
|
||||
@ -1135,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);
|
||||
@ -1262,6 +1257,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
ACTF("Spawning cmplog forkserver");
|
||||
afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
|
||||
// TODO: this is semi-nice
|
||||
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
|
||||
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
|
||||
@ -1272,70 +1268,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
ACTF("Spawning qemu_taint forkserver");
|
||||
|
||||
u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
|
||||
setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
|
||||
|
||||
afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv);
|
||||
afl->taint_fsrv.taint_mode = 1;
|
||||
afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
|
||||
ck_free(afl->taint_fsrv.target_path);
|
||||
afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind));
|
||||
afl->taint_fsrv.target_path = find_afl_binary("afl-qemu-taint", argv[0]);
|
||||
afl->argv_taint[0] = find_afl_binary("afl-qemu-taint", argv[0]);
|
||||
if (!afl->argv_taint[0])
|
||||
FATAL(
|
||||
"Cannot find 'afl-qemu-taint', read qemu_taint/README.md on how to "
|
||||
"build it.");
|
||||
u32 idx = optind - 1, offset = 0;
|
||||
do {
|
||||
|
||||
idx++;
|
||||
offset++;
|
||||
afl->argv_taint[offset] = argv[idx];
|
||||
|
||||
} while (argv[idx] != NULL);
|
||||
|
||||
if (afl->fsrv.use_stdin)
|
||||
unsetenv("AFL_TAINT_INPUT");
|
||||
else
|
||||
setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1);
|
||||
afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child_output);
|
||||
|
||||
afl->taint_input_file = alloc_printf("%s/taint/.input", afl->out_dir);
|
||||
int fd = open(afl->taint_input_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
|
||||
if (fd < 0)
|
||||
FATAL("Cannot create taint inpu file '%s'", afl->taint_input_file);
|
||||
lseek(fd, MAX_FILE, SEEK_SET);
|
||||
ck_write(fd, "\0", 1, afl->taint_input_file);
|
||||
|
||||
if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
|
||||
|
||||
OKF("Taint forkserver successfully started");
|
||||
|
||||
const rlim_t kStackSize = 128L * 1024L * 1024L; // min stack size = 128 Mb
|
||||
struct rlimit rl;
|
||||
rl.rlim_cur = kStackSize;
|
||||
if (getrlimit(RLIMIT_STACK, &rl) != 0)
|
||||
WARNF("Setting a higher stack size failed!");
|
||||
|
||||
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
|
||||
u8 *tmp1 = ck_maybe_grow(BUF_PARAMS(eff), MAX_FILE + 4096);
|
||||
u8 *tmp2 = ck_maybe_grow(BUF_PARAMS(ex), MAX_FILE + 4096);
|
||||
u8 *tmp3 = ck_maybe_grow(BUF_PARAMS(in_scratch), MAX_FILE + 4096);
|
||||
u8 *tmp4 = ck_maybe_grow(BUF_PARAMS(out), MAX_FILE + 4096);
|
||||
u8 *tmp5 = ck_maybe_grow(BUF_PARAMS(out_scratch), MAX_FILE + 4096);
|
||||
#undef BUF_PARAMS
|
||||
if (!tmp1 || !tmp2 || !tmp3 || !tmp4 || !tmp5)
|
||||
FATAL("memory issues. me hungry, feed me!");
|
||||
|
||||
}
|
||||
|
||||
perform_dry_run(afl);
|
||||
|
||||
cull_queue(afl);
|
||||
@ -1410,7 +1342,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
break;
|
||||
case 1:
|
||||
if (afl->limit_time_sig == 0 && !afl->custom_only &&
|
||||
!afl->python_only && !afl->taint_mode) {
|
||||
!afl->python_only) {
|
||||
|
||||
afl->limit_time_sig = -1;
|
||||
afl->limit_time_puppet = 0;
|
||||
@ -1598,11 +1530,8 @@ stop_fuzzing:
|
||||
|
||||
}
|
||||
|
||||
if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv);
|
||||
if (afl->taint_mode) afl_fsrv_deinit(&afl->taint_fsrv);
|
||||
afl_fsrv_deinit(&afl->fsrv);
|
||||
if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
|
||||
if (afl->argv_taint) { ck_free(afl->argv_taint); }
|
||||
ck_free(afl->fsrv.target_path);
|
||||
ck_free(afl->fsrv.out_file);
|
||||
ck_free(afl->sync_id);
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user