mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
351 Commits
Author | SHA1 | Date | |
---|---|---|---|
1c64048d0f | |||
0a6084f361 | |||
9532499ef5 | |||
1d56de6c1d | |||
266b51a842 | |||
cc1fe2f2d2 | |||
43214d6b46 | |||
2f28ecd3a5 | |||
73a629d6f2 | |||
0a251f93e0 | |||
1cf4738487 | |||
af14acf2c1 | |||
a7537b5511 | |||
15e799f7ae | |||
5f0a9c90c8 | |||
9ff9ff2ad2 | |||
d86b13384f | |||
17a4e9fadf | |||
ce513c4f3e | |||
ce92adcb9b | |||
e94cc1fae0 | |||
32fe047894 | |||
d1bc0207cc | |||
69f8c62955 | |||
83df65a66b | |||
c3a6e7e870 | |||
d0ab83a202 | |||
b5d1a021ef | |||
e9fb5f4cbc | |||
212bb990b7 | |||
8e984c2aa0 | |||
7f435ec5f1 | |||
47faf3dd33 | |||
c4e52e20c9 | |||
2c5e103278 | |||
7a6867e2f8 | |||
8044ae28be | |||
b38837f4ff | |||
c25479264d | |||
e9b3da5d96 | |||
132b57cf03 | |||
ee548df05f | |||
052d74b16c | |||
83281503b3 | |||
b604f5eafc | |||
220dc4a43d | |||
457f627101 | |||
4f695b6f4c | |||
3ec1b23743 | |||
0ba09ee85a | |||
67dac15226 | |||
9cf8637fab | |||
50e76fce12 | |||
432638404f | |||
1e38c10efb | |||
701fb95d24 | |||
7b5a18428e | |||
7d7a8c7c39 | |||
a422fcaa40 | |||
fee58a4d1b | |||
3ecafde29d | |||
8428b18d2a | |||
9c953ab51f | |||
f181a8307b | |||
84b9d551fd | |||
8f8555dfdf | |||
464c27082a | |||
3aa7d8081d | |||
fb84103ffb | |||
c270646722 | |||
87da1e7af6 | |||
9b71f7e5e4 | |||
9945c1648b | |||
e5d24827de | |||
a6521e89fc | |||
5e36fb32a8 | |||
fb0181f5bc | |||
6fa2c213ef | |||
9ec223c844 | |||
558a82891a | |||
4fc16b542e | |||
ff40359a60 | |||
e99d7e9730 | |||
b60663c031 | |||
32db31b555 | |||
a1129b67c2 | |||
8a1cf3f0f9 | |||
0bb59ba116 | |||
e4a0237cbc | |||
d8f5502d83 | |||
45d0e4765e | |||
9a1d526ed4 | |||
ebc6f52868 | |||
a19b31bf82 | |||
28251a495a | |||
f4592a8fb4 | |||
b29d91edf5 | |||
986af28df2 | |||
27abecbff5 | |||
33141cf8a3 | |||
8551d8e48e | |||
32558bc807 | |||
934cdc32f4 | |||
699ebaa8e2 | |||
44ad516edd | |||
fd9a7e719d | |||
e51f1ea5a5 | |||
22d3a5e90a | |||
673ace2a4b | |||
4a6d66d8c5 | |||
1978629d87 | |||
5b06166144 | |||
a0fab35bbf | |||
420b202124 | |||
fb14e55cc9 | |||
e2434cf8c6 | |||
d94681186d | |||
58a710d192 | |||
716eb226b2 | |||
cb3631a322 | |||
bd1d148f83 | |||
7e0c9a36ef | |||
bbfff7d472 | |||
e048d95660 | |||
970d75d681 | |||
51f3a81037 | |||
8190436f8f | |||
08bcaa135f | |||
c4e5f75728 | |||
1064c7114e | |||
0281872ddf | |||
c6bf23377d | |||
2d650f8c22 | |||
19631851f6 | |||
f30ca1476c | |||
0712d44cbc | |||
15f3210d93 | |||
9864d9c189 | |||
bd36aac60a | |||
4a859aff70 | |||
8fc727e597 | |||
585ec04503 | |||
a1c93f24d4 | |||
f6c89ec3a9 | |||
3d8f054580 | |||
6d364dd2cb | |||
8ed6207b5c | |||
c8354d7516 | |||
79f873a597 | |||
8850e1a5bf | |||
194188fe56 | |||
cc74efa35e | |||
e7f2770275 | |||
af277a0b56 | |||
4163f47e09 | |||
b2aa8b03d9 | |||
e1d20706ca | |||
76888fdf59 | |||
e6e38d1703 | |||
44060590b4 | |||
38bed607d1 | |||
ed63364a77 | |||
55bd24b0c7 | |||
f18c2eb8ae | |||
898353c87a | |||
d5d8d664d0 | |||
409e4ae945 | |||
f335c48686 | |||
9d82c3cf5e | |||
491cee669f | |||
e0d1529061 | |||
1cddd51662 | |||
6041b1c486 | |||
349fed3fcd | |||
b708cf7d45 | |||
a267ff1ab5 | |||
8e0c776137 | |||
4512377fa1 | |||
9439ba1dac | |||
9c9c4a6b2b | |||
6efe51a8a7 | |||
593940c39a | |||
8ea19d4266 | |||
b7bcc50c61 | |||
e939677726 | |||
ca17ec3fe9 | |||
54d9668580 | |||
16b674c652 | |||
25ad992c62 | |||
37f1b7cddb | |||
729445b64f | |||
185f443659 | |||
c101a3f5ab | |||
cf9cb73afe | |||
071fcac430 | |||
a74ec89461 | |||
630d2a934b | |||
d5758c138b | |||
149b0021b7 | |||
68f46f6178 | |||
cd576fa59d | |||
320f26d26f | |||
c661587128 | |||
486e5365d9 | |||
8e809d8593 | |||
ea9ba53cdb | |||
1ba48a5ba0 | |||
7cb00b69f0 | |||
cbe8f0a9d0 | |||
da8b464e67 | |||
13350bf22f | |||
5ce55d87ec | |||
fc401f1acc | |||
fe39e4dfdf | |||
49b77207dd | |||
35a448ee92 | |||
3f9f00a798 | |||
ffe5619a9d | |||
3b194e1690 | |||
45b6508339 | |||
22921c493f | |||
f32811922e | |||
6cfa27d78a | |||
8e3ca8eaa9 | |||
4550613f58 | |||
015fde3703 | |||
827ecd61f6 | |||
565da10a8f | |||
d64c0e8887 | |||
0b8c44cbb1 | |||
a22f4dd1ac | |||
952e5b47eb | |||
b3f5b566b0 | |||
0b3332d579 | |||
a76e375d5c | |||
8b21c2e472 | |||
23718e5198 | |||
031aa240bc | |||
7944009a65 | |||
4eb06bb54b | |||
bd5308d839 | |||
b508532c78 | |||
fb9888a068 | |||
11f25747a9 | |||
8ebed3471f | |||
85684cd8b7 | |||
2585a33005 | |||
1bbeef48e1 | |||
7f3317110e | |||
298ff5c7d0 | |||
c3f65bff5b | |||
2323c30b5b | |||
80f4b32f0b | |||
16e362d2b9 | |||
23da490f26 | |||
ff107714f1 | |||
7e4703c328 | |||
ae41cedafe | |||
a879f72131 | |||
131df8bec9 | |||
89557d1607 | |||
7959808384 | |||
ecb0601bc1 | |||
30c0991543 | |||
9cddbc0420 | |||
2fa31dab60 | |||
4898db80cb | |||
aa3856261d | |||
3e04dbd5a1 | |||
72b46a07d6 | |||
2ba88dcd8a | |||
1ddb70e0d9 | |||
024a88a6bb | |||
af10c05ac3 | |||
a46a733dbe | |||
b015e4f07a | |||
44928a0265 | |||
d90328f6be | |||
ce9b4698fe | |||
9a33a29b4a | |||
b6e65f9882 | |||
6c163910ee | |||
9151cb9ba2 | |||
204ae75d7b | |||
f2d9b0096e | |||
67d2e6319b | |||
5e10f660e8 | |||
0da0b5cba0 | |||
67d7c364f6 | |||
67d58e2437 | |||
c2b04bdf6c | |||
6513bca07e | |||
0b0366d9b4 | |||
f465a75b65 | |||
4314e59af9 | |||
a84c958647 | |||
1ec2615a3e | |||
2077309c8d | |||
08d3169df4 | |||
3cc0445e27 | |||
ee77fe4094 | |||
133dfc8b69 | |||
a8726b8254 | |||
c5963f707c | |||
383b280531 | |||
95276f7da6 | |||
e1d4621796 | |||
e137b40eb5 | |||
4d929f80fb | |||
6b79e1f76d | |||
5a26656ea1 | |||
abb0d47985 | |||
b126a5d5a8 | |||
571031a467 | |||
2981f2025f | |||
c3a6065a21 | |||
60bb1afc72 | |||
84a320f834 | |||
88bd460100 | |||
90adc2cb85 | |||
7c8d823396 | |||
83790d65af | |||
70bd0f799d | |||
cbe029664e | |||
cade0214db | |||
2f5cdb72c8 | |||
0aed549df1 | |||
75fa1ac3b0 | |||
b5a00312e0 | |||
37697127dc | |||
8acc8b5389 | |||
8644c42482 | |||
20e63078f0 | |||
95fd080ca1 | |||
7d0af01d8b | |||
0f0230b068 | |||
869c602b99 | |||
3144f72e1c | |||
147b0a151c | |||
29102d6bf1 | |||
4fd145c52e | |||
e6d4d29af5 | |||
139665c01d | |||
509b991607 | |||
c671ecb511 | |||
1aa7c87ea8 | |||
00abb999e3 | |||
fc5cfc6cb3 | |||
25c3a29004 | |||
118cc88429 | |||
0dc9967984 |
@ -32,7 +32,8 @@ if CLANG_FORMAT_BIN is None:
|
||||
p = subprocess.Popen(["clang-format-10", "--version"], stdout=subprocess.PIPE)
|
||||
o, _ = p.communicate()
|
||||
o = str(o, "utf-8")
|
||||
o = o[len("clang-format version "):].strip()
|
||||
o = re.sub(r".*ersion ", "", o)
|
||||
#o = o[len("clang-format version "):].strip()
|
||||
o = o[:o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
|
65
.dockerignore
Normal file
65
.dockerignore
Normal file
@ -0,0 +1,65 @@
|
||||
.test
|
||||
.test2
|
||||
.sync_tmp
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
ld
|
||||
in
|
||||
out
|
||||
core*
|
||||
afl-analyze
|
||||
afl-as
|
||||
afl-clang
|
||||
afl-clang\+\+
|
||||
afl-clang-fast
|
||||
afl-clang-fast\+\+
|
||||
afl-clang-lto
|
||||
afl-clang-lto\+\+
|
||||
afl-fuzz
|
||||
afl-g\+\+
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-g\+\+-fast
|
||||
afl-gotcpu
|
||||
afl-ld
|
||||
afl-ld-lto
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-tmin
|
||||
afl-analyze.8
|
||||
afl-as.8
|
||||
afl-clang-fast\+\+.8
|
||||
afl-clang-fast.8
|
||||
afl-clang-lto.8
|
||||
afl-clang-lto\+\+.8
|
||||
afl-cmin.8
|
||||
afl-cmin.bash.8
|
||||
afl-fuzz.8
|
||||
afl-gcc.8
|
||||
afl-gcc-fast.8
|
||||
afl-g\+\+-fast.8
|
||||
afl-gotcpu.8
|
||||
afl-plot.8
|
||||
afl-showmap.8
|
||||
afl-system-config.8
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output
|
||||
unicorn_mode/unicornafl
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
test/unittests/unit_rand
|
||||
test/unittests/unit_hash
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,8 +1,15 @@
|
||||
.test
|
||||
.test2
|
||||
.sync_tmp
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
ld
|
||||
in
|
||||
out
|
||||
core*
|
||||
afl-analyze
|
||||
afl-as
|
||||
afl-clang
|
||||
@ -41,13 +48,10 @@ afl-system-config.8
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
as
|
||||
ld
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
unicorn_mode/unicornafl
|
||||
core\.*
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
@ -55,3 +59,7 @@ test/unittests/unit_rand
|
||||
test/unittests/unit_hash
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
||||
|
@ -51,8 +51,9 @@ script:
|
||||
- gcc -v
|
||||
- clang -v
|
||||
- sudo -E ./afl-system-config
|
||||
- sudo sysctl -w kernel.shmmax=10000000000
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export LLVM_CONFIG=`pwd`/"$NAME" ; make source-only ASAN_BUILD=1 ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$TRAVIS_CPU_ARCH" = "amd64" ]; then make distrib ASAN_BUILD=1 ; fi
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then echo DEBUG ; find / -name llvm-config.h 2>/dev/null; apt-cache search clang | grep clang- ; apt-cache search llvm | grep llvm- ; dpkg -l | egrep 'clang|llvm'; echo DEBUG ; export LLVM_CONFIG=llvm-config-6.0 ; make ASAN_BUILD=1 ; cd qemu_mode && sh ./build_qemu_support.sh ; cd .. ; fi
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then export LLVM_CONFIG=llvm-config-6.0 ; make ASAN_BUILD=1 ; cd qemu_mode && sh ./build_qemu_support.sh ; cd .. ; fi
|
||||
- make tests
|
||||
# - travis_terminate 0
|
||||
|
@ -1,5 +1,7 @@
|
||||
# How to submit a Pull Request to AFLplusplus
|
||||
|
||||
All contributions (pull requests) must be made against our `dev` branch.
|
||||
|
||||
Each modified source file, before merging, must be formatted.
|
||||
|
||||
```
|
||||
@ -18,5 +20,5 @@ No camel case at all and use the AFL's macros wherever possible
|
||||
(e.g. WARNF, FATAL, MAP_SIZE, ...).
|
||||
|
||||
Remember that AFLplusplus has to build and run on many platforms, so
|
||||
generalize your Makefiles (or your patches to our pre-existing Makefiles)
|
||||
to be as much generic as possible.
|
||||
generalize your Makefiles/GNUmakefile (or your patches to our pre-existing
|
||||
Makefiles) to be as much generic as possible.
|
||||
|
28
Dockerfile
28
Dockerfile
@ -5,7 +5,7 @@
|
||||
# has focal has gcc-10 but not g++-10 ...
|
||||
#
|
||||
|
||||
FROM ubuntu:20.04
|
||||
FROM ubuntu:20.04 AS aflplusplus
|
||||
MAINTAINER afl++ team <afl@aflplus.plus>
|
||||
LABEL "about"="AFLplusplus docker image"
|
||||
|
||||
@ -20,11 +20,11 @@ RUN apt-get update && apt-get upgrade -y && \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
wget vim jupp nano \
|
||||
wget vim jupp nano bash-completion \
|
||||
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||
libpixman-1-dev
|
||||
|
||||
RUN echo deb http://apt.llvm.org/focal/ llvm-toolchain-focal main >> /etc/apt/sources.list && \
|
||||
RUN echo deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main >> /etc/apt/sources.list && \
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
|
||||
RUN echo deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main >> /etc/apt/sources.list && \
|
||||
@ -46,17 +46,19 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
|
||||
RUN rm -rf /var/cache/apt/archives/*
|
||||
|
||||
ARG CC=gcc-10
|
||||
ARG CXX=g++-10
|
||||
ARG LLVM_CONFIG=llvm-config-11
|
||||
ENV LLVM_CONFIG=llvm-config-11
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
|
||||
RUN git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
RUN cd AFLplusplus && export REAL_CXX=g++-10 && make distrib && \
|
||||
make install && make clean
|
||||
RUN git clone https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN cd /afl-cov && make install && cd ..
|
||||
|
||||
RUN git clone https://github.com/vanhauser-thc/afl-cov afl-cov
|
||||
RUN cd afl-cov && make install
|
||||
COPY . /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
|
||||
RUN export REAL_CXX=g++-10 && export CC=gcc-10 && \
|
||||
export CXX=g++-10 && make clean && \
|
||||
make distrib && make install && make clean
|
||||
|
||||
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
|
||||
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
RUN echo 'export PS1="[afl++]$PS1"' >> ~/.bashrc
|
||||
ENV IS_DOCKER="1"
|
||||
|
36
GNUmakefile
36
GNUmakefile
@ -56,8 +56,10 @@ endif
|
||||
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifndef SOURCE_DATE_EPOCH
|
||||
#CFLAGS_OPT += -march=native
|
||||
SPECIAL_PERFORMANCE += -march=native
|
||||
endif
|
||||
endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
@ -65,7 +67,7 @@ endif
|
||||
|
||||
ifeq "$(shell uname)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS=-lkstat
|
||||
LDFLAGS=-lkstat -lrt
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
@ -95,8 +97,14 @@ ifneq "$(shell uname -m)" "x86_64"
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
|
||||
ifdef DEBUG
|
||||
$(info Compiling DEBUG version of binaries)
|
||||
CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror
|
||||
else
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
endif
|
||||
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
|
||||
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
|
||||
@ -196,7 +204,8 @@ else
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
LDFLAGS += -ldl -lrt
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
@ -254,13 +263,13 @@ ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int ma
|
||||
else
|
||||
SHMAT_OK=0
|
||||
override CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations -lrt
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifdef TEST_MMAP
|
||||
SHMAT_OK=0
|
||||
override CFLAGS += -DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations -lrt
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
@ -268,7 +277,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
man: $(MANPAGES)
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
@cd test ; ./test-all.sh
|
||||
@rm -f test/errors
|
||||
|
||||
performance-tests: performance-test
|
||||
@ -302,6 +311,7 @@ help:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "=========================================="
|
||||
@ -455,10 +465,10 @@ code-format:
|
||||
./.custom-format.py -i llvm_mode/*.h
|
||||
./.custom-format.py -i llvm_mode/*.cc
|
||||
./.custom-format.py -i gcc_plugin/*.c
|
||||
#./.custom-format.py -i gcc_plugin/*.h
|
||||
@#./.custom-format.py -i gcc_plugin/*.h
|
||||
./.custom-format.py -i gcc_plugin/*.cc
|
||||
./.custom-format.py -i custom_mutators/*/*.c
|
||||
./.custom-format.py -i custom_mutators/*/*.h
|
||||
@#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-(
|
||||
./.custom-format.py -i examples/*/*.c
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i test/*.c
|
||||
@ -549,9 +559,9 @@ source-only: all
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
#$(MAKE) -C examples/afl_network_proxy
|
||||
#$(MAKE) -C examples/socket_fuzzing
|
||||
#$(MAKE) -C examples/argv_fuzzing
|
||||
@#$(MAKE) -C examples/afl_network_proxy
|
||||
@#$(MAKE) -C examples/socket_fuzzing
|
||||
@#$(MAKE) -C examples/argv_fuzzing
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@ -587,6 +597,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
|
||||
|
22
TODO.md
22
TODO.md
@ -1,20 +1,20 @@
|
||||
# TODO list for AFL++
|
||||
|
||||
## Roadmap 2.66+
|
||||
## Roadmap 2.67+
|
||||
|
||||
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
|
||||
- namespace for targets? e.g. network
|
||||
- learn from honggfuzz (mutations, maybe ptrace?)
|
||||
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||
- afl-plot to support multiple plot_data
|
||||
|
||||
## Further down the road
|
||||
|
||||
afl-fuzz:
|
||||
- ascii_only mode for mutation output - or use a custom mutator for this?
|
||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||
- 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)
|
||||
@ -22,7 +22,7 @@ gcc_plugin:
|
||||
- better instrumentation (seems to be better with gcc-9+)
|
||||
|
||||
qemu_mode:
|
||||
- update to 5.x (if the performance bug if gone)
|
||||
- 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?)
|
||||
@ -30,3 +30,15 @@ qemu_mode:
|
||||
persistent mode
|
||||
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
|
||||
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses
|
||||
|
||||
## Ideas
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
14
afl-plot
14
afl-plot
@ -68,6 +68,15 @@ if [ ! -f "$inputdir/plot_data" ]; then
|
||||
|
||||
fi
|
||||
|
||||
LINES=`cat "$inputdir/plot_data" | wc -l`
|
||||
|
||||
if [ "$LINES" -lt 3 ]; then
|
||||
|
||||
echo "[-] Error: plot_data carries too little data, let it run longer." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
BANNER="`cat "$inputdir/fuzzer_stats" 2> /dev/null | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
|
||||
|
||||
test "$BANNER" = "" && BANNER="(none)"
|
||||
@ -118,6 +127,9 @@ set key outside
|
||||
set autoscale xfixmin
|
||||
set autoscale xfixmax
|
||||
|
||||
set xlabel "all times in UTC" font "small"
|
||||
|
||||
set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
|
||||
'' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
|
||||
@ -127,6 +139,7 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$outputdir/low_freq.png'
|
||||
|
||||
set ytics 1
|
||||
plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
|
||||
'' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
|
||||
@ -135,6 +148,7 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$outputdir/exec_speed.png'
|
||||
|
||||
set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
|
||||
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
test "$1" = "-h" && {
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
|
||||
echo
|
||||
echo $0
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
test "$1" = "-h" && {
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo $0 [-s] output_directory
|
||||
echo
|
||||
echo Options:
|
||||
@ -162,7 +162,8 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
|
||||
ALIVE_CNT=$((ALIVE_CNT + 1))
|
||||
|
||||
EXEC_SEC=$((execs_done / RUN_UNIX))
|
||||
EXEC_SEC=0
|
||||
test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
|
||||
PATH_PERC=$((cur_path * 100 / paths_total))
|
||||
|
||||
TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
|
||||
@ -184,7 +185,9 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
echo " ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
|
||||
fi
|
||||
|
||||
if [ $EXEC_SEC -lt 100 ]; then
|
||||
if [ $EXEC_SEC -eq 0 ]; then
|
||||
echo " ${YELLOW}no data yet, 0 execs/sec${NC}"
|
||||
elif [ $EXEC_SEC -lt 100 ]; then
|
||||
echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
|
||||
fi
|
||||
|
||||
|
@ -68,7 +68,12 @@ else:
|
||||
argv = sys.argv[1:]
|
||||
for i in range(len(argv)):
|
||||
if ".cur_input" in argv[i]:
|
||||
argv[i] = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
|
||||
# Get the Wine translated path using the winepath tool
|
||||
arg_translated = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
|
||||
# Remove the spurious LF at the end of the path
|
||||
if len(arg_translated) > 0 and arg_translated[-1] == '\n':
|
||||
arg_translated = arg_translated[:-1]
|
||||
argv[i] = arg_translated
|
||||
break
|
||||
|
||||
print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))
|
||||
|
@ -1,4 +1,9 @@
|
||||
# production ready custom mutators
|
||||
# Custom Mutators
|
||||
|
||||
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).
|
||||
|
||||
## Production-Ready Custom Mutators
|
||||
|
||||
This directory holds ready to use custom mutators.
|
||||
Just type "make" in the individual subdirectories.
|
||||
@ -10,3 +15,22 @@ Use with e.g.
|
||||
and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
|
||||
|
||||
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
|
||||
|
||||
## 3rd Party Custom Mutators
|
||||
|
||||
### Superion Mutators
|
||||
|
||||
Adrian Tiron ported the Superion grammar fuzzer to afl++, it is WIP and
|
||||
requires cmake (among other things):
|
||||
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
|
||||
|
||||
### libprotobuf Mutators
|
||||
|
||||
There are two WIP protobuf projects, that require work to be working though:
|
||||
|
||||
transforms protobuf raw:
|
||||
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
|
||||
|
||||
has a transform function you need to fill for your protobuf format, however
|
||||
needs to be ported to the updated afl++ custom mutator API (not much work):
|
||||
https://github.com/thebabush/afl-libprotobuf-mutator
|
||||
|
17
custom_mutators/honggfuzz/Makefile
Normal file
17
custom_mutators/honggfuzz/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
|
||||
|
||||
all: honggfuzz.so
|
||||
|
||||
honggfuzz.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz.so honggfuzz.c mangle.c ../../src/afl-performance.c
|
||||
|
||||
update:
|
||||
@# seriously? --unlink is a dud option? sigh ...
|
||||
rm -f mangle.c mangle.h honggfuzz.h
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.c
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.h
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/honggfuzz.h
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ *.so core
|
12
custom_mutators/honggfuzz/README.md
Normal file
12
custom_mutators/honggfuzz/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# custum mutator: honggfuzz mangle
|
||||
|
||||
this is the very good honggfuzz mutator in mangle.c as a custom mutator
|
||||
module for afl++. It is the original mangle.c, mangle.h and honggfuzz.h
|
||||
with a lot of mocking around it :-)
|
||||
|
||||
just type `make` to build
|
||||
|
||||
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/honggfuzz/honggfuzz.so afl-fuzz ...```
|
||||
|
||||
> Original repository: https://github.com/google/honggfuzz
|
||||
> Source commit: d0fbcb0373c32436b8fb922e6937da93b17291f5
|
0
custom_mutators/honggfuzz/common.h
Normal file
0
custom_mutators/honggfuzz/common.h
Normal file
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||
#define BUF_VAR(type, name) \
|
||||
type * name##_buf; \
|
||||
size_t name##_size;
|
||||
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
|
||||
#define BUF_PARAMS(struct, name) \
|
||||
(void **)&struct->name##_buf, &struct->name##_size
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
143
custom_mutators/honggfuzz/honggfuzz.c
Normal file
143
custom_mutators/honggfuzz/honggfuzz.c
Normal file
@ -0,0 +1,143 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "custom_mutator_helpers.h"
|
||||
#include "mangle.h"
|
||||
|
||||
#define NUMBER_OF_MUTATIONS 5
|
||||
|
||||
uint8_t * queue_input;
|
||||
size_t queue_input_size;
|
||||
afl_state_t * afl_struct;
|
||||
run_t run;
|
||||
honggfuzz_t global;
|
||||
struct _dynfile_t dynfile;
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
run_t * run;
|
||||
u8 * mutator_buf;
|
||||
unsigned int seed;
|
||||
unsigned int extras_cnt, a_extras_cnt;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
|
||||
|
||||
perror("mutator_buf alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
run.dynfile = &dynfile;
|
||||
run.global = &global;
|
||||
data->afl = afl;
|
||||
data->seed = seed;
|
||||
data->run = &run;
|
||||
afl_struct = afl;
|
||||
|
||||
run.global->mutate.maxInputSz = MAX_FILE;
|
||||
run.global->mutate.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||
run.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||
run.global->timing.lastCovUpdate = 6;
|
||||
|
||||
// global->feedback.cmpFeedback
|
||||
// global->feedback.cmpFeedbackMap
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/* When a new queue entry is added we check if there are new dictionary
|
||||
entries to add to honggfuzz structure */
|
||||
|
||||
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
if (run.global->mutate.dictionaryCnt >= 1024) return;
|
||||
|
||||
while (data->extras_cnt < data->afl->extras_cnt &&
|
||||
run.global->mutate.dictionaryCnt < 1024) {
|
||||
|
||||
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||
data->afl->extras[data->extras_cnt].data,
|
||||
data->afl->extras[data->extras_cnt].len);
|
||||
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||
data->afl->extras[data->extras_cnt].len;
|
||||
run.global->mutate.dictionaryCnt++;
|
||||
data->extras_cnt++;
|
||||
|
||||
}
|
||||
|
||||
while (data->a_extras_cnt < data->afl->a_extras_cnt &&
|
||||
run.global->mutate.dictionaryCnt < 1024) {
|
||||
|
||||
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||
data->afl->a_extras[data->a_extras_cnt].data,
|
||||
data->afl->a_extras[data->a_extras_cnt].len);
|
||||
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||
data->afl->a_extras[data->a_extras_cnt].len;
|
||||
run.global->mutate.dictionaryCnt++;
|
||||
data->a_extras_cnt++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* we could set only_printable if is_ascii is set ... let's see
|
||||
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) {
|
||||
|
||||
//run.global->cfg.only_printable = ...
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/* here we run the honggfuzz mutator, which is really good */
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
/* set everything up, costly ... :( */
|
||||
memcpy(data->mutator_buf, buf, buf_size);
|
||||
queue_input = data->mutator_buf;
|
||||
run.dynfile->data = data->mutator_buf;
|
||||
queue_input_size = buf_size;
|
||||
run.dynfile->size = buf_size;
|
||||
*out_buf = data->mutator_buf;
|
||||
|
||||
/* the mutation */
|
||||
mangle_mangleContent(&run, NUMBER_OF_MUTATIONS);
|
||||
|
||||
/* return size of mutated data */
|
||||
return run.dynfile->size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->mutator_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
385
custom_mutators/honggfuzz/honggfuzz.h
Normal file
385
custom_mutators/honggfuzz/honggfuzz.h
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
*
|
||||
* honggfuzz - core structures and macros
|
||||
* -----------------------------------------
|
||||
*
|
||||
* Author: Robert Swiecki <swiecki@google.com>
|
||||
*
|
||||
* Copyright 2010-2018 by Google Inc. 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HF_HONGGFUZZ_H_
|
||||
#define _HF_HONGGFUZZ_H_
|
||||
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "libhfcommon/util.h"
|
||||
|
||||
#define PROG_NAME "honggfuzz"
|
||||
#define PROG_VERSION "2.3"
|
||||
|
||||
/* Name of the template which will be replaced with the proper name of the file */
|
||||
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||
|
||||
/* Default name of the report created with some architectures */
|
||||
#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
|
||||
|
||||
/* Default stack-size of created threads. */
|
||||
#define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */
|
||||
|
||||
/* Name of envvar which indicates sequential number of fuzzer */
|
||||
#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
|
||||
|
||||
/* Name of envvar which indicates that the netDriver should be used */
|
||||
#define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
|
||||
|
||||
/* Name of envvar which indicates honggfuzz's log level in use */
|
||||
#define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
|
||||
|
||||
/* Number of crash verifier iterations before tag crash as stable */
|
||||
#define _HF_VERIFIER_ITER 5
|
||||
|
||||
/* Size (in bytes) for report data to be stored in stack before written to file */
|
||||
#define _HF_REPORT_SIZE 32768
|
||||
|
||||
/* Perf bitmap size */
|
||||
#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
|
||||
#define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
|
||||
/* Maximum number of PC guards (=trace-pc-guard) we support */
|
||||
#define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
|
||||
|
||||
/* Maximum size of the input file in bytes (1 MiB) */
|
||||
#define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL)
|
||||
|
||||
/* Default maximum size of produced inputs */
|
||||
#define _HF_INPUT_DEFAULT_SIZE (1024ULL * 8)
|
||||
|
||||
/* Per-thread bitmap */
|
||||
#define _HF_PERTHREAD_BITMAP_FD 1018
|
||||
/* FD used to report back used int/str constants from the fuzzed process */
|
||||
#define _HF_CMP_BITMAP_FD 1019
|
||||
/* FD used to log inside the child process */
|
||||
#define _HF_LOG_FD 1020
|
||||
/* FD used to represent the input file */
|
||||
#define _HF_INPUT_FD 1021
|
||||
/* FD used to pass coverage feedback from the fuzzed process */
|
||||
#define _HF_COV_BITMAP_FD 1022
|
||||
#define _HF_BITMAP_FD _HF_COV_BITMAP_FD /* Old name for _HF_COV_BITMAP_FD */
|
||||
/* FD used to pass data to a persistent process */
|
||||
#define _HF_PERSISTENT_FD 1023
|
||||
|
||||
/* Input file as a string */
|
||||
#define _HF_INPUT_FILE_PATH "/dev/fd/" HF_XSTR(_HF_INPUT_FD)
|
||||
|
||||
/* Maximum number of supported execve() args */
|
||||
#define _HF_ARGS_MAX 2048
|
||||
|
||||
/* Message indicating that the fuzzed process is ready for new data */
|
||||
static const uint8_t HFReadyTag = 'R';
|
||||
|
||||
/* Maximum number of active fuzzing threads */
|
||||
#define _HF_THREAD_MAX 1024U
|
||||
|
||||
/* Persistent-binary signature - if found within file, it means it's a persistent mode binary */
|
||||
#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
|
||||
/* HF NetDriver signature - if found within file, it means it's a NetDriver-based binary */
|
||||
#define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
|
||||
|
||||
/* printf() nonmonetary separator. According to MacOSX's man it's supported there as well */
|
||||
#define _HF_NONMON_SEP "'"
|
||||
|
||||
typedef enum {
|
||||
_HF_DYNFILE_NONE = 0x0,
|
||||
_HF_DYNFILE_INSTR_COUNT = 0x1,
|
||||
_HF_DYNFILE_BRANCH_COUNT = 0x2,
|
||||
_HF_DYNFILE_BTS_EDGE = 0x10,
|
||||
_HF_DYNFILE_IPT_BLOCK = 0x20,
|
||||
_HF_DYNFILE_SOFT = 0x40,
|
||||
} dynFileMethod_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t cpuInstrCnt;
|
||||
uint64_t cpuBranchCnt;
|
||||
uint64_t bbCnt;
|
||||
uint64_t newBBCnt;
|
||||
uint64_t softCntPc;
|
||||
uint64_t softCntEdge;
|
||||
uint64_t softCntCmp;
|
||||
} hwcnt_t;
|
||||
|
||||
typedef enum {
|
||||
_HF_STATE_UNSET = 0,
|
||||
_HF_STATE_STATIC,
|
||||
_HF_STATE_DYNAMIC_DRY_RUN,
|
||||
_HF_STATE_DYNAMIC_MAIN,
|
||||
_HF_STATE_DYNAMIC_MINIMIZE,
|
||||
} fuzzState_t;
|
||||
|
||||
typedef enum {
|
||||
HF_MAYBE = -1,
|
||||
HF_NO = 0,
|
||||
HF_YES = 1,
|
||||
} tristate_t;
|
||||
|
||||
struct _dynfile_t {
|
||||
size_t size;
|
||||
uint64_t cov[4];
|
||||
size_t idx;
|
||||
int fd;
|
||||
uint64_t timeExecUSecs;
|
||||
char path[PATH_MAX];
|
||||
struct _dynfile_t* src;
|
||||
uint32_t refs;
|
||||
uint8_t* data;
|
||||
TAILQ_ENTRY(_dynfile_t) pointers;
|
||||
};
|
||||
|
||||
typedef struct _dynfile_t dynfile_t;
|
||||
|
||||
struct strings_t {
|
||||
size_t len;
|
||||
TAILQ_ENTRY(strings_t) pointers;
|
||||
char s[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t pcGuardMap[_HF_PC_GUARD_MAX];
|
||||
uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
|
||||
uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
|
||||
uint64_t pidNewPC[_HF_THREAD_MAX];
|
||||
uint64_t pidNewEdge[_HF_THREAD_MAX];
|
||||
uint64_t pidNewCmp[_HF_THREAD_MAX];
|
||||
uint64_t guardNb;
|
||||
uint64_t pidTotalPC[_HF_THREAD_MAX];
|
||||
uint64_t pidTotalEdge[_HF_THREAD_MAX];
|
||||
uint64_t pidTotalCmp[_HF_THREAD_MAX];
|
||||
} feedback_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t cnt;
|
||||
struct {
|
||||
uint8_t val[32];
|
||||
uint32_t len;
|
||||
} valArr[1024 * 16];
|
||||
} cmpfeedback_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
size_t threadsMax;
|
||||
size_t threadsFinished;
|
||||
uint32_t threadsActiveCnt;
|
||||
pthread_t mainThread;
|
||||
pid_t mainPid;
|
||||
pthread_t threads[_HF_THREAD_MAX];
|
||||
} threads;
|
||||
struct {
|
||||
const char* inputDir;
|
||||
const char* outputDir;
|
||||
DIR* inputDirPtr;
|
||||
size_t fileCnt;
|
||||
size_t testedFileCnt;
|
||||
const char* fileExtn;
|
||||
size_t maxFileSz;
|
||||
size_t newUnitsAdded;
|
||||
char workDir[PATH_MAX];
|
||||
const char* crashDir;
|
||||
const char* covDirNew;
|
||||
bool saveUnique;
|
||||
size_t dynfileqMaxSz;
|
||||
size_t dynfileqCnt;
|
||||
dynfile_t* dynfileqCurrent;
|
||||
dynfile_t* dynfileq2Current;
|
||||
TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq;
|
||||
bool exportFeedback;
|
||||
} io;
|
||||
struct {
|
||||
int argc;
|
||||
const char* const* cmdline;
|
||||
bool nullifyStdio;
|
||||
bool fuzzStdin;
|
||||
const char* externalCommand;
|
||||
const char* postExternalCommand;
|
||||
const char* feedbackMutateCommand;
|
||||
bool netDriver;
|
||||
bool persistent;
|
||||
uint64_t asLimit;
|
||||
uint64_t rssLimit;
|
||||
uint64_t dataLimit;
|
||||
uint64_t coreLimit;
|
||||
uint64_t stackLimit;
|
||||
bool clearEnv;
|
||||
char* env_ptrs[128];
|
||||
char env_vals[128][4096];
|
||||
sigset_t waitSigSet;
|
||||
} exe;
|
||||
struct {
|
||||
time_t timeStart;
|
||||
time_t runEndTime;
|
||||
time_t tmOut;
|
||||
time_t lastCovUpdate;
|
||||
int64_t timeOfLongestUnitUSecs;
|
||||
bool tmoutVTALRM;
|
||||
} timing;
|
||||
struct {
|
||||
struct {
|
||||
uint8_t val[256];
|
||||
size_t len;
|
||||
} dictionary[1024];
|
||||
size_t dictionaryCnt;
|
||||
const char* dictionaryFile;
|
||||
size_t mutationsMax;
|
||||
unsigned mutationsPerRun;
|
||||
size_t maxInputSz;
|
||||
} mutate;
|
||||
struct {
|
||||
bool useScreen;
|
||||
char cmdline_txt[65];
|
||||
int64_t lastDisplayUSecs;
|
||||
} display;
|
||||
struct {
|
||||
bool useVerifier;
|
||||
bool exitUponCrash;
|
||||
const char* reportFile;
|
||||
size_t dynFileIterExpire;
|
||||
bool only_printable;
|
||||
bool minimize;
|
||||
bool switchingToFDM;
|
||||
} cfg;
|
||||
struct {
|
||||
bool enable;
|
||||
bool del_report;
|
||||
} sanitizer;
|
||||
struct {
|
||||
fuzzState_t state;
|
||||
feedback_t* covFeedbackMap;
|
||||
int covFeedbackFd;
|
||||
cmpfeedback_t* cmpFeedbackMap;
|
||||
int cmpFeedbackFd;
|
||||
bool cmpFeedback;
|
||||
const char* blacklistFile;
|
||||
uint64_t* blacklist;
|
||||
size_t blacklistCnt;
|
||||
bool skipFeedbackOnTimeout;
|
||||
uint64_t maxCov[4];
|
||||
dynFileMethod_t dynFileMethod;
|
||||
hwcnt_t hwCnts;
|
||||
} feedback;
|
||||
struct {
|
||||
size_t mutationsCnt;
|
||||
size_t crashesCnt;
|
||||
size_t uniqueCrashesCnt;
|
||||
size_t verifiedCrashesCnt;
|
||||
size_t blCrashesCnt;
|
||||
size_t timeoutedCnt;
|
||||
} cnts;
|
||||
struct {
|
||||
bool enabled;
|
||||
int serverSocket;
|
||||
int clientSocket;
|
||||
} socketFuzzer;
|
||||
struct {
|
||||
pthread_rwlock_t dynfileq;
|
||||
pthread_mutex_t feedback;
|
||||
pthread_mutex_t report;
|
||||
pthread_mutex_t state;
|
||||
pthread_mutex_t input;
|
||||
pthread_mutex_t timing;
|
||||
} mutex;
|
||||
|
||||
/* For the Linux code */
|
||||
struct {
|
||||
int exeFd;
|
||||
uint64_t dynamicCutOffAddr;
|
||||
bool disableRandomization;
|
||||
void* ignoreAddr;
|
||||
const char* symsBlFile;
|
||||
char** symsBl;
|
||||
size_t symsBlCnt;
|
||||
const char* symsWlFile;
|
||||
char** symsWl;
|
||||
size_t symsWlCnt;
|
||||
uintptr_t cloneFlags;
|
||||
tristate_t useNetNs;
|
||||
bool kernelOnly;
|
||||
bool useClone;
|
||||
} arch_linux;
|
||||
/* For the NetBSD code */
|
||||
struct {
|
||||
void* ignoreAddr;
|
||||
const char* symsBlFile;
|
||||
char** symsBl;
|
||||
size_t symsBlCnt;
|
||||
const char* symsWlFile;
|
||||
char** symsWl;
|
||||
size_t symsWlCnt;
|
||||
} arch_netbsd;
|
||||
} honggfuzz_t;
|
||||
|
||||
typedef enum {
|
||||
_HF_RS_UNKNOWN = 0,
|
||||
_HF_RS_WAITING_FOR_INITIAL_READY = 1,
|
||||
_HF_RS_WAITING_FOR_READY = 2,
|
||||
_HF_RS_SEND_DATA = 3,
|
||||
} runState_t;
|
||||
|
||||
typedef struct {
|
||||
honggfuzz_t* global;
|
||||
pid_t pid;
|
||||
int64_t timeStartedUSecs;
|
||||
char crashFileName[PATH_MAX];
|
||||
uint64_t pc;
|
||||
uint64_t backtrace;
|
||||
uint64_t access;
|
||||
int exception;
|
||||
char report[_HF_REPORT_SIZE];
|
||||
bool mainWorker;
|
||||
unsigned mutationsPerRun;
|
||||
dynfile_t* dynfile;
|
||||
bool staticFileTryMore;
|
||||
uint32_t fuzzNo;
|
||||
int persistentSock;
|
||||
runState_t runState;
|
||||
bool tmOutSignaled;
|
||||
char* args[_HF_ARGS_MAX + 1];
|
||||
int perThreadCovFeedbackFd;
|
||||
unsigned triesLeft;
|
||||
dynfile_t* current;
|
||||
#if !defined(_HF_ARCH_DARWIN)
|
||||
timer_t timerId;
|
||||
#endif // !defined(_HF_ARCH_DARWIN)
|
||||
hwcnt_t hwCnts;
|
||||
|
||||
struct {
|
||||
/* For Linux code */
|
||||
uint8_t* perfMmapBuf;
|
||||
uint8_t* perfMmapAux;
|
||||
int cpuInstrFd;
|
||||
int cpuBranchFd;
|
||||
int cpuIptBtsFd;
|
||||
} arch_linux;
|
||||
} run_t;
|
||||
|
||||
#endif
|
106
custom_mutators/honggfuzz/input.h
Normal file
106
custom_mutators/honggfuzz/input.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef _HG_INPUT_
|
||||
#define _HG_INPUT_
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef __clang__
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "honggfuzz.h"
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
/*
|
||||
* Go-style defer scoped implementation
|
||||
*
|
||||
* If compiled with clang, use: -fblocks -lBlocksRuntime
|
||||
*
|
||||
* Example of use:
|
||||
*
|
||||
* {
|
||||
* int fd = open(fname, O_RDONLY);
|
||||
* if (fd == -1) {
|
||||
* error(....);
|
||||
* return;
|
||||
* }
|
||||
* defer { close(fd); };
|
||||
* ssize_t sz = read(fd, buf, sizeof(buf));
|
||||
* ...
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STRMERGE(a, b) a##b
|
||||
#define _STRMERGE(a, b) __STRMERGE(a, b)
|
||||
#ifdef __clang__
|
||||
#if __has_extension(blocks)
|
||||
static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
|
||||
(*dfunc)();
|
||||
}
|
||||
|
||||
#define defer \
|
||||
void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
|
||||
__attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
|
||||
|
||||
#else /* __has_extension(blocks) */
|
||||
#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
|
||||
#endif /* __has_extension(blocks) */
|
||||
#else /* !__clang__, e.g.: gcc */
|
||||
|
||||
#define __block
|
||||
#define _DEFER(a, count) \
|
||||
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
|
||||
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
|
||||
__attribute__((unused)); \
|
||||
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
|
||||
#define defer _DEFER(a, __COUNTER__)
|
||||
#endif /* ifdef __clang__ */
|
||||
|
||||
#define HF_MIN(x, y) (x <= y ? x : y)
|
||||
#define HF_MAX(x, y) (x >= y ? x : y)
|
||||
#define ATOMIC_GET
|
||||
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
|
||||
#define HF_ATTR_UNUSED __attribute__((unused))
|
||||
#define util_Malloc(x) malloc(x)
|
||||
|
||||
extern uint8_t * queue_input;
|
||||
extern size_t queue_input_size;
|
||||
extern afl_state_t * afl_struct;
|
||||
|
||||
inline void wmb() { }
|
||||
inline void LOG_F(const char *format, ...) { }
|
||||
static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
|
||||
return min + rand_below(afl_struct, max - min + 1);
|
||||
}
|
||||
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||
|
||||
static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
|
||||
*buf = queue_input;
|
||||
run->dynfile->data = queue_input;
|
||||
run->dynfile->size = queue_input_size;
|
||||
return queue_input_size;
|
||||
}
|
||||
static inline void input_setSize(run_t* run, size_t sz) {
|
||||
run->dynfile->size = sz;
|
||||
}
|
||||
static inline void util_turnToPrintable(uint8_t* buf, size_t sz) {
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = buf[i] % 95 + 32;
|
||||
}
|
||||
static inline void util_rndBuf(uint8_t* buf, size_t sz) {
|
||||
if (sz == 0) return;
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = (uint8_t)rand_below(afl_struct, 256);
|
||||
}
|
||||
static inline uint8_t util_rndPrintable() {
|
||||
return 32 + rand_below(afl_struct, 127 - 32);
|
||||
}
|
||||
static inline void util_rndBufPrintable(uint8_t* buf, size_t sz) {
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = util_rndPrintable();
|
||||
}
|
||||
|
||||
#endif
|
1
custom_mutators/honggfuzz/libhfcommon
Symbolic link
1
custom_mutators/honggfuzz/libhfcommon
Symbolic link
@ -0,0 +1 @@
|
||||
.
|
1
custom_mutators/honggfuzz/log.h
Symbolic link
1
custom_mutators/honggfuzz/log.h
Symbolic link
@ -0,0 +1 @@
|
||||
common.h
|
1037
custom_mutators/honggfuzz/mangle.c
Normal file
1037
custom_mutators/honggfuzz/mangle.c
Normal file
File diff suppressed because it is too large
Load Diff
31
custom_mutators/honggfuzz/mangle.h
Normal file
31
custom_mutators/honggfuzz/mangle.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
*
|
||||
* honggfuzz - buffer mangling routines
|
||||
* -----------------------------------------
|
||||
*
|
||||
* Author: Robert Swiecki <swiecki@google.com>
|
||||
*
|
||||
* Copyright 2010-2018 by Google Inc. 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HF_MANGLE_H_
|
||||
#define _HF_MANGLE_H_
|
||||
|
||||
#include "honggfuzz.h"
|
||||
|
||||
extern void mangle_mangleContent(run_t* run, int speed_factor);
|
||||
|
||||
#endif
|
1
custom_mutators/honggfuzz/util.h
Symbolic link
1
custom_mutators/honggfuzz/util.h
Symbolic link
@ -0,0 +1 @@
|
||||
common.h
|
@ -3,10 +3,12 @@
|
||||
# charset
|
||||
"\\ansi"
|
||||
"\\mac"
|
||||
"\\pc"
|
||||
"\\pca"
|
||||
|
||||
# font table
|
||||
"\\fnil"
|
||||
"\\fRoman"
|
||||
"\\fswiss"
|
||||
"\\fmodern"
|
||||
"\\fscript"
|
||||
@ -28,6 +30,7 @@
|
||||
"\\cb"
|
||||
|
||||
# pictures
|
||||
"\\pict"
|
||||
"\\macpict"
|
||||
"\\pmmetafile"
|
||||
"\\wmetafile"
|
||||
@ -40,36 +43,15 @@
|
||||
"\\pich"
|
||||
"\\picwgoal"
|
||||
"\\pichgoal"
|
||||
"\\picscalex"
|
||||
"\\picscaley"
|
||||
"\\picscaled"
|
||||
"\\piccropt"
|
||||
"\\piccropb"
|
||||
"\\piccropl"
|
||||
"\\piccropr"
|
||||
"\\brdrs"
|
||||
"\\brdrdb"
|
||||
"\\brdrth"
|
||||
"\\brdrsh"
|
||||
"\\brdrdot"
|
||||
"\\brdrhair"
|
||||
"\\brdrw"
|
||||
"\\brdrcf"
|
||||
"\\shading"
|
||||
"\\bghoriz"
|
||||
"\\bgvert"
|
||||
"\\bgfdiag"
|
||||
"\\bgbdiag"
|
||||
"\\bgcross"
|
||||
"\\bgdcross"
|
||||
"\\bgdkhoriz"
|
||||
"\\bgdkvert"
|
||||
"\\bgdkfdiag"
|
||||
"\\bgdkbdiag"
|
||||
"\\bgdkcross"
|
||||
"\\bgdkdcross"
|
||||
"\\cfpat"
|
||||
"\\cbpat"
|
||||
"\\bin"
|
||||
# these strings are probably not necessary
|
||||
"MM_TEXT"
|
||||
"MM_LOMETRIC"
|
||||
"MM_HIMETRIC"
|
||||
@ -86,25 +68,31 @@
|
||||
"PU_HIENGLISH"
|
||||
"PU_TWIPS"
|
||||
|
||||
# headers and gooters
|
||||
"\headerr"
|
||||
"\headerf"
|
||||
"\footerl"
|
||||
"\footerr"
|
||||
"\footerf"
|
||||
# headers and footers
|
||||
"\\headerl"
|
||||
"\\headerr"
|
||||
"\\headerf"
|
||||
"\\footerl"
|
||||
"\\footerr"
|
||||
"\\footerf"
|
||||
|
||||
# misc
|
||||
"\\chftn"
|
||||
"\\*\\footnote"
|
||||
"\\*\\annotation"
|
||||
"\\xe"
|
||||
"\\txe"
|
||||
"\\rxe"
|
||||
"\\bxe"
|
||||
"\\ixe"
|
||||
"\\tcf"
|
||||
"\\tcl"
|
||||
"\\*\\bkmkstart"
|
||||
"\\*\\bkmkend"
|
||||
"\\bkmkcolf"
|
||||
"\\bkmkcoll"
|
||||
|
||||
# metadata
|
||||
"\\info"
|
||||
"\\title"
|
||||
"\\subject"
|
||||
"\\author"
|
||||
@ -128,10 +116,13 @@
|
||||
"\\nofwords"
|
||||
"\\nofchars"
|
||||
"\\id"
|
||||
"\\field"
|
||||
"\\flddirty"
|
||||
"\\fldedit"
|
||||
"\\fldlock"
|
||||
"\\fldpriv"
|
||||
"\\*\\fldinst"
|
||||
"\\fldrslt"
|
||||
|
||||
# objects
|
||||
"\\objemb"
|
||||
@ -166,16 +157,14 @@
|
||||
# macintosh editor
|
||||
"\\bkmkpub"
|
||||
"\\pubauto"
|
||||
"\\objalias"
|
||||
"\\objsect"
|
||||
|
||||
# formating
|
||||
"\\deftab"
|
||||
"\\hyphhotz"
|
||||
"\\linestart"
|
||||
"\\fracwidth"
|
||||
"\\*\nextfile"
|
||||
"\\*\template"
|
||||
"\\*\\nextfile"
|
||||
"\\*\\template"
|
||||
"\\makebackup"
|
||||
"\\defformat"
|
||||
"\\psover"
|
||||
|
@ -9,6 +9,54 @@ 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.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
|
||||
- added -b option to bind to a specific CPU
|
||||
- eliminated CPU affinity race condition for -S/-M runs
|
||||
- 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
|
||||
- llvm_mode:
|
||||
- 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 :)
|
||||
- added neverzero counting to trace-pc/pcgard
|
||||
- fixes for laf-intel float splitting (thanks to mark-griffin for
|
||||
reporting)
|
||||
- fixes for llvm 4.0
|
||||
- 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 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
|
||||
was given to which function during compilation
|
||||
- LTO: single block functions were not implemented by default, fixed
|
||||
- LTO: AFL_LLVM_SKIP_NEVERZERO behaviour was inversed, fixed
|
||||
- setting AFL_LLVM_LAF_SPLIT_FLOATS now activates
|
||||
AFL_LLVM_LAF_SPLIT_COMPARES
|
||||
- support for -E and -shared compilation runs
|
||||
- added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz
|
||||
- added afl-frida gum solution to examples/afl_frida (mostly imported
|
||||
from https://github.com/meme/hotwax/)
|
||||
- small fixes to afl-plot, afl-whatsup and man page creation
|
||||
- new README, added FAQ
|
||||
|
||||
|
||||
### Version ++2.66c (release)
|
||||
- renamed the main branch on Github to "stable"
|
||||
- renamed master/slave to main/secondary
|
||||
|
218
docs/FAQ.md
Normal file
218
docs/FAQ.md
Normal file
@ -0,0 +1,218 @@
|
||||
# Frequently asked questions about afl++
|
||||
|
||||
## Contents
|
||||
|
||||
* [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl)
|
||||
* [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed)
|
||||
* [How do I fuzz a network service?](#how-to-fuzz-a-network-service)
|
||||
* [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program)
|
||||
* [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)
|
||||
|
||||
## What is the difference between afl and afl++?
|
||||
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting in
|
||||
2013/2014, and when he left Google end of 2017 he stopped developing it.
|
||||
|
||||
At the end of 2019 the Google fuzzing team took over maintance of AFL, however
|
||||
it is only accepting PR from the community and is not developing enhancements
|
||||
anymore.
|
||||
|
||||
In the second quarter of 2019, 1 1/2 years after no further development of
|
||||
AFL had happened and it became clear there would be none coming, afl++
|
||||
was born, where initially first community patches were collected and applied
|
||||
for bugs and enhancements. Then from various AFL spin-offs - mostly academic
|
||||
research - features were integrated. This already resulted in a much advanced
|
||||
AFL.
|
||||
|
||||
Until the end of 2019 the afl++ team had grown to four active developers which
|
||||
then implemented their own research and feature, making it now by far the most
|
||||
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)
|
||||
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".
|
||||
|
||||
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.
|
||||
|
||||
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!
|
||||
|
||||
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/)
|
||||
|
||||
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) -
|
||||
however a better option is AFLnet ([https://github.com/aflnet/aflnet](https://github.com/aflnet/aflnet))
|
||||
which allows you to define network state with different type of data packets.
|
||||
|
||||
## How do I fuzz a GUI program?
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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"
|
||||
|
||||
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:
|
||||
```
|
||||
function() {
|
||||
A:
|
||||
some
|
||||
code
|
||||
B:
|
||||
if (x) goto C; else goto D;
|
||||
C:
|
||||
some code
|
||||
goto D
|
||||
D:
|
||||
some code
|
||||
goto B
|
||||
E:
|
||||
return
|
||||
}
|
||||
```
|
||||
Every code block between two jump locations is a `basic block`.
|
||||
|
||||
An `edge` is then the unique relationship between two `basic blocks` (from the
|
||||
code example above):
|
||||
```
|
||||
Block A
|
||||
|
|
||||
v
|
||||
Block B <------+
|
||||
/ \ |
|
||||
v v |
|
||||
Block C Block D --+
|
||||
\
|
||||
v
|
||||
Block E
|
||||
```
|
||||
Every line between two blocks is an `edge`.
|
||||
|
||||
## 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 other external data,
|
||||
reaction to timing, etc. then in some of the re-executions with the same data
|
||||
the result in the edge information will be different accross runs.
|
||||
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.
|
||||
|
||||
## How can I improve the stability value
|
||||
|
||||
For fuzzing a 100% stable target that covers all edges is the best.
|
||||
A 90% stable target that covers all edges is however better than a 100% stable
|
||||
target that ignores 10% of the edges.
|
||||
|
||||
With instability you basically have a partial coverage loss on an edge, with
|
||||
ignore you have a full loss on that edge.
|
||||
|
||||
There are functions that are unstable, but also provide value to coverage, eg
|
||||
init functions that use fuzz data as input for example.
|
||||
If however it is a function that has nothing to do with the input data is the
|
||||
source, e.g. checking jitter, or is a hash map function etc. then it should
|
||||
not be instrumented.
|
||||
|
||||
To be able to make this decision the following process will allow you to
|
||||
identify the functions with variable edges so you can make this decision.
|
||||
|
||||
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.
|
||||
|
||||
1. First step: Identify which edge ID numbers are unstable
|
||||
|
||||
run the target with `export AFL_DEBUG=1` for a few minutes then terminate.
|
||||
The out/fuzzer_stats file will then show the edge IDs that were identified
|
||||
as unstable.
|
||||
|
||||
2. Second step: Find the responsible function.
|
||||
|
||||
a) For LTO instrumented binaries this can be documented during compile
|
||||
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
|
||||
llvm_mode/afl-llvm-rt.o.c to write a backtrace to a file if the ID in
|
||||
__afl_area_ptr[*guard] is one of the unstable edge IDs.
|
||||
(Example code is already there).
|
||||
Then recompile and reinstall llvm_mode and rebuild your target.
|
||||
Run the recompiled target with afl-fuzz for a while and then check the
|
||||
file that you wrote with the backtrace information.
|
||||
Alternatively you can use `gdb` to hook __sanitizer_cov_trace_pc_guard_init
|
||||
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 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!
|
||||
|
||||
Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md)
|
||||
If PCGUARD is used, then you need to follow this guide (needs llvm 12+!):
|
||||
[http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation)
|
||||
|
||||
Only deny those functions from instrumentation that provide no value
|
||||
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)
|
@ -8,12 +8,17 @@
|
||||
|
||||
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.
|
||||
|
||||
If your target is a library use examples/afl_frida/.
|
||||
|
||||
If your target is non-linux then use unicorn_mode/.
|
||||
|
||||
|
||||
## QEMU
|
||||
|
||||
@ -57,6 +62,20 @@
|
||||
As it is included in afl++ this needs no URL.
|
||||
|
||||
|
||||
## AFL FRIDA
|
||||
|
||||
If you want to fuzz a binary-only shared library then you can fuzz it with
|
||||
frida-gum via examples/afl_frida/, you will have to write a harness to
|
||||
call the target function in the library, use afl-frida.c as a template.
|
||||
|
||||
|
||||
## AFL UNTRACER
|
||||
|
||||
If you want to fuzz a binary-only shared library then you can fuzz it with
|
||||
examples/afl_untracer/, use afl-untracer.c as a template.
|
||||
It is slower than AFL FRIDA (see above).
|
||||
|
||||
|
||||
## DYNINST
|
||||
|
||||
Dyninst is a binary instrumentation framework similar to Pintool and
|
||||
|
@ -36,7 +36,7 @@ size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf,
|
||||
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);
|
||||
size_t afl_custom_trim(void *data, uint8_t **out_buf);
|
||||
int32_t afl_custom_post_trim(void *data, int success) {
|
||||
int32_t afl_custom_post_trim(void *data, int success);
|
||||
size_t afl_custom_havoc_mutation(void *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t max_size);
|
||||
uint8_t afl_custom_havoc_mutation_probability(void *data);
|
||||
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename);
|
||||
|
@ -121,18 +121,16 @@ 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.
|
||||
(recommended)
|
||||
|
||||
- AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target
|
||||
binary based on string compare and memory compare functions.
|
||||
afl-fuzz will automatically get these transmitted when starting to
|
||||
fuzz.
|
||||
(not recommended!)
|
||||
|
||||
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
|
||||
are then later combined.
|
||||
|
||||
- AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given
|
||||
to which function. This helps to identify functions with variable bytes
|
||||
or which functions were touched by an input.
|
||||
- AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than
|
||||
the default 0x10000. A value of 0 or empty sets the map address to be
|
||||
dynamic (the original afl way, which is slower)
|
||||
@ -204,14 +202,15 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
See llvm_mode/README.laf-intel.md for more information.
|
||||
|
||||
### INSTRUMENT_FILE
|
||||
### INSTRUMENT LIST (selectively instrument files and functions)
|
||||
|
||||
This feature allows selectively instrumentation of the source
|
||||
|
||||
- Setting AFL_LLVM_INSTRUMENT_FILE with a filename will only instrument those
|
||||
files that match the names listed in this file.
|
||||
- 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
|
||||
listed in the specified file.
|
||||
|
||||
See llvm_mode/README.instrument_file.md for more information.
|
||||
See llvm_mode/README.instrument_list.md for more information.
|
||||
|
||||
### NOT_ZERO
|
||||
|
||||
@ -243,7 +242,7 @@ Then there are a few specific features that are only available in the gcc_plugin
|
||||
- Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those
|
||||
files that match the names listed in this file (one filename per line).
|
||||
|
||||
See gcc_plugin/README.instrument_file.md for more information.
|
||||
See gcc_plugin/README.instrument_list.md for more information.
|
||||
|
||||
## 3) Settings for afl-fuzz
|
||||
|
||||
@ -254,15 +253,6 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
useful if you can't change the defaults (e.g., no root access to the
|
||||
system) and are OK with some performance loss.
|
||||
|
||||
- Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to
|
||||
fork + execve() call for every tested input. This is useful mostly when
|
||||
working with unruly libraries that create threads or do other crazy
|
||||
things when initializing (before the instrumentation has a chance to run).
|
||||
|
||||
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.
|
||||
|
||||
- AFL_EXIT_WHEN_DONE causes afl-fuzz to terminate when all existing paths
|
||||
have been fuzzed and there were no new finds for a while. This would be
|
||||
normally indicated by the cycle counter in the UI turning green. May be
|
||||
@ -273,6 +263,9 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
the target. This must be equal or larger than the size the target was
|
||||
compiled with.
|
||||
|
||||
- Setting AFL_DISABLE_TRIM tells afl-fuzz to no trim test cases. This is
|
||||
usually a bad idea!
|
||||
|
||||
- Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core
|
||||
on Linux systems. This slows things down, but lets you run more instances
|
||||
of afl-fuzz than would be prudent (if you really want to).
|
||||
@ -338,6 +331,13 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
|
||||
- In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace.
|
||||
|
||||
- Setting AFL_CYCLE_SCHEDULES will switch to a different schedule everytime
|
||||
a cycle is finished.
|
||||
|
||||
- Setting AFL_EXPAND_HAVOC_NOW will start in the extended havoc mode that
|
||||
includes costly mutations. afl-fuzz automatically enables this mode when
|
||||
deemed useful otherwise.
|
||||
|
||||
- Setting AFL_PRELOAD causes AFL to set LD_PRELOAD for the target binary
|
||||
without disrupting the afl-fuzz process itself. This is useful, among other
|
||||
things, for bootstrapping libdislocator.so.
|
||||
@ -365,6 +365,15 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
for an existing out folder, even if a different `-i` was provided.
|
||||
Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir.
|
||||
|
||||
- Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to
|
||||
fork + execve() call for every tested input. This is useful mostly when
|
||||
working with unruly libraries that create threads or do other crazy
|
||||
things when initializing (before the instrumentation has a chance to run).
|
||||
|
||||
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.
|
||||
|
||||
- Outdated environment variables that are that not supported anymore:
|
||||
AFL_DEFER_FORKSRV
|
||||
AFL_PERSISTENT
|
||||
|
@ -99,7 +99,15 @@ example may be:
|
||||
This is not a concern if you use @@ without -f and let afl-fuzz come up with the
|
||||
file name.
|
||||
|
||||
## 3) Multi-system parallelization
|
||||
## 3) 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.
|
||||
|
||||
## 4) 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
|
||||
@ -176,7 +184,7 @@ 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.
|
||||
|
||||
## 4) Remote monitoring and data collection
|
||||
## 5) 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
|
||||
@ -200,7 +208,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).
|
||||
|
||||
## 5) Asymmetric setups
|
||||
## 6) Asymmetric setups
|
||||
|
||||
It is perhaps worth noting that all of the following is permitted:
|
||||
|
||||
|
@ -67,7 +67,7 @@ to get to the important parts in the code.
|
||||
|
||||
If you are only interested in specific parts of the code being fuzzed, you can
|
||||
instrument_files the files that are actually relevant. This improves the speed and
|
||||
accuracy of afl. See llvm_mode/README.instrument_file.md
|
||||
accuracy of afl. See llvm_mode/README.instrument_list.md
|
||||
|
||||
Also use the InsTrim mode on larger binaries, this improves performance and
|
||||
coverage a lot.
|
||||
|
BIN
docs/screenshot.png
Normal file
BIN
docs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
10
dynamic_list.txt
Normal file
10
dynamic_list.txt
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"__afl_area_ptr";
|
||||
"__afl_manual_init";
|
||||
"__afl_persistent_loop";
|
||||
"__afl_auto_init";
|
||||
"__afl_area_initial";
|
||||
"__afl_prev_loc";
|
||||
"__sanitizer_cov_trace_pc_guard";
|
||||
"__sanitizer_cov_trace_pc_guard_init";
|
||||
};
|
23
examples/afl_frida/GNUmakefile
Normal file
23
examples/afl_frida/GNUmakefile
Normal file
@ -0,0 +1,23 @@
|
||||
ifdef DEBUG
|
||||
OPT=-O0 -D_DEBUG=\"1\"
|
||||
else
|
||||
OPT=-O3 -funroll-loops
|
||||
endif
|
||||
|
||||
all: afl-frida libtestinstr.so
|
||||
|
||||
libfrida-gum.a:
|
||||
@echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest
|
||||
@exit 1
|
||||
|
||||
afl-frida: afl-frida.c libfrida-gum.a
|
||||
$(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-llvm-rt.o libfrida-gum.a -ldl -lresolv -pthread
|
||||
|
||||
libtestinstr.so: libtestinstr.c
|
||||
$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
|
||||
|
||||
clean:
|
||||
rm -f afl-frida *~ core *.o libtestinstr.so
|
||||
|
||||
deepclean: clean
|
||||
rm -f libfrida-gum.a frida-gum*
|
2
examples/afl_frida/Makefile
Normal file
2
examples/afl_frida/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
all:
|
||||
@echo please use GNU make, thanks!
|
34
examples/afl_frida/README.md
Normal file
34
examples/afl_frida/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# afl-frida - faster fuzzing of binary-only libraries
|
||||
|
||||
## Introduction
|
||||
|
||||
afl-frida is an example skeleton file which can easily be used to fuzz
|
||||
a closed source library.
|
||||
|
||||
It requires less memory and is x5-10 faster than qemu_mode but does not
|
||||
provide interesting features like compcov or cmplog.
|
||||
|
||||
## How-to
|
||||
|
||||
### Modify afl-frida.c
|
||||
|
||||
Read and modify afl-frida.c then `make`.
|
||||
To adapt afl-frida.c to your needs, read the header of the file and then
|
||||
search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
|
||||
|
||||
### Fuzzing
|
||||
|
||||
Example (after modifying afl-frida.c to your needs and compile it):
|
||||
```
|
||||
LD_LIBRARY_PATH=/path/to/the/target/library afl-fuzz -i in -o out -- ./afl-frida
|
||||
```
|
||||
(or even remote via afl-network-proxy).
|
||||
|
||||
# Speed and stability
|
||||
|
||||
The speed is very good, about x12 of fork() qemu_mode.
|
||||
However the stability is low. Reason is currently unknown.
|
||||
|
||||
# Background
|
||||
|
||||
This code is copied for a larger part from https://github.com/meme/hotwax
|
541
examples/afl_frida/afl-frida.c
Normal file
541
examples/afl_frida/afl-frida.c
Normal file
@ -0,0 +1,541 @@
|
||||
/*
|
||||
american fuzzy lop++ - afl-frida skeleton example
|
||||
-------------------------------------------------
|
||||
|
||||
Copyright 2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Written mostly by meme -> https://github.com/meme/hotwax
|
||||
|
||||
Modificationy by Marc Heuse <mh@mh-sec.de>
|
||||
|
||||
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
|
||||
|
||||
HOW-TO
|
||||
======
|
||||
|
||||
You only need to change the following:
|
||||
|
||||
1. set the defines and function call parameters.
|
||||
2. dl load the library you want to fuzz, lookup the functions you need
|
||||
and setup the calls to these.
|
||||
3. in the while loop you call the functions in the necessary order -
|
||||
incl the cleanup. the cleanup is important!
|
||||
|
||||
Just look these steps up in the code, look for "// STEP x:"
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/shm.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <sys/wait.h>
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
|
||||
int debug = 0;
|
||||
|
||||
// STEP 1:
|
||||
|
||||
// The presets are for the example libtestinstr.so:
|
||||
|
||||
/* What is the name of the library to fuzz */
|
||||
#define TARGET_LIBRARY "libtestinstr.so"
|
||||
|
||||
/* What is the name of the function to fuzz */
|
||||
#define TARGET_FUNCTION "testinstr"
|
||||
|
||||
/* here you need to specify the parameter for the target function */
|
||||
static void *(*o_function)(uint8_t *, int);
|
||||
|
||||
// END STEP 1
|
||||
|
||||
#include "frida-gum.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type())
|
||||
G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM,
|
||||
FAKE_EVENT_SINK, GObject)
|
||||
|
||||
struct _GumFakeEventSink {
|
||||
|
||||
GObject parent;
|
||||
GumEventType mask;
|
||||
|
||||
};
|
||||
|
||||
GumEventSink *gum_fake_event_sink_new(void);
|
||||
void gum_fake_event_sink_reset(GumFakeEventSink *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
static void gum_fake_event_sink_iface_init(gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
static void gum_fake_event_sink_finalize(GObject *obj);
|
||||
static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink);
|
||||
static void gum_fake_event_sink_process(GumEventSink *sink, const GumEvent *ev);
|
||||
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
|
||||
gpointer user_data);
|
||||
void afl_setup(void);
|
||||
void afl_start_forkserver(void);
|
||||
int __afl_persistent_loop(unsigned int max_cnt);
|
||||
|
||||
static void gum_fake_event_sink_class_init(GumFakeEventSinkClass *klass) {
|
||||
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
object_class->finalize = gum_fake_event_sink_finalize;
|
||||
|
||||
}
|
||||
|
||||
static void gum_fake_event_sink_iface_init(gpointer g_iface,
|
||||
gpointer iface_data) {
|
||||
|
||||
GumEventSinkInterface *iface = (GumEventSinkInterface *)g_iface;
|
||||
iface->query_mask = gum_fake_event_sink_query_mask;
|
||||
iface->process = gum_fake_event_sink_process;
|
||||
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED(GumFakeEventSink, gum_fake_event_sink, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE(GUM_TYPE_EVENT_SINK,
|
||||
gum_fake_event_sink_iface_init))
|
||||
|
||||
#include "../../config.h"
|
||||
|
||||
// Shared memory fuzzing.
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int * __afl_fuzz_len;
|
||||
extern unsigned char *__afl_fuzz_ptr;
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
|
||||
// Because we do our own logging.
|
||||
extern uint8_t * __afl_area_ptr;
|
||||
static __thread guint64 previous_pc;
|
||||
|
||||
// Frida stuff below.
|
||||
typedef struct {
|
||||
|
||||
GumAddress base_address;
|
||||
guint64 code_start, code_end;
|
||||
|
||||
} range_t;
|
||||
|
||||
inline static void afl_maybe_log(guint64 current_pc) {
|
||||
|
||||
// fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc);
|
||||
|
||||
current_pc = (current_pc >> 4) ^ (current_pc << 8);
|
||||
current_pc &= MAP_SIZE - 1;
|
||||
|
||||
__afl_area_ptr[current_pc ^ previous_pc]++;
|
||||
previous_pc = current_pc >> 1;
|
||||
|
||||
}
|
||||
|
||||
static void on_basic_block(GumCpuContext *context, gpointer user_data) {
|
||||
|
||||
afl_maybe_log((guint64)user_data);
|
||||
|
||||
}
|
||||
|
||||
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
|
||||
gpointer user_data) {
|
||||
|
||||
range_t *range = (range_t *)user_data;
|
||||
|
||||
const cs_insn *instr;
|
||||
gboolean begin = TRUE;
|
||||
while (gum_stalker_iterator_next(iterator, &instr)) {
|
||||
|
||||
if (begin) {
|
||||
|
||||
if (instr->address >= range->code_start &&
|
||||
instr->address <= range->code_end) {
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, on_basic_block,
|
||||
(gpointer)instr->address, NULL);
|
||||
begin = FALSE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gum_stalker_iterator_keep(iterator);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void gum_fake_event_sink_init(GumFakeEventSink *self) {
|
||||
|
||||
}
|
||||
|
||||
static void gum_fake_event_sink_finalize(GObject *obj) {
|
||||
|
||||
G_OBJECT_CLASS(gum_fake_event_sink_parent_class)->finalize(obj);
|
||||
|
||||
}
|
||||
|
||||
GumEventSink *gum_fake_event_sink_new(void) {
|
||||
|
||||
GumFakeEventSink *sink;
|
||||
sink = (GumFakeEventSink *)g_object_new(GUM_TYPE_FAKE_EVENT_SINK, NULL);
|
||||
return GUM_EVENT_SINK(sink);
|
||||
|
||||
}
|
||||
|
||||
void gum_fake_event_sink_reset(GumFakeEventSink *self) {
|
||||
|
||||
}
|
||||
|
||||
static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
typedef struct library_list {
|
||||
|
||||
uint8_t *name;
|
||||
uint64_t addr_start, addr_end;
|
||||
|
||||
} library_list_t;
|
||||
|
||||
#define MAX_LIB_COUNT 256
|
||||
static library_list_t liblist[MAX_LIB_COUNT];
|
||||
static u32 liblist_cnt;
|
||||
|
||||
void read_library_information() {
|
||||
|
||||
#if defined(__linux__)
|
||||
FILE *f;
|
||||
u8 buf[1024], *b, *m, *e, *n;
|
||||
|
||||
if ((f = fopen("/proc/self/maps", "r")) == NULL) {
|
||||
|
||||
fprintf(stderr, "Error: cannot open /proc/self/maps\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
if (debug) fprintf(stderr, "Library list:\n");
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
|
||||
if (strstr(buf, " r-x")) {
|
||||
|
||||
if (liblist_cnt >= MAX_LIB_COUNT) {
|
||||
|
||||
fprintf(
|
||||
stderr,
|
||||
"Warning: too many libraries to old, maximum count of %d reached\n",
|
||||
liblist_cnt);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
b = buf;
|
||||
m = index(buf, '-');
|
||||
e = index(buf, ' ');
|
||||
if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' ');
|
||||
if (n &&
|
||||
((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
|
||||
n = NULL;
|
||||
else
|
||||
n++;
|
||||
if (b && m && e && n && *n) {
|
||||
|
||||
*m++ = 0;
|
||||
*e = 0;
|
||||
if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
|
||||
|
||||
if (rindex(n, '/') != NULL) {
|
||||
|
||||
n = rindex(n, '/');
|
||||
n++;
|
||||
|
||||
}
|
||||
|
||||
liblist[liblist_cnt].name = strdup(n);
|
||||
liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
|
||||
liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
|
||||
if (debug)
|
||||
fprintf(
|
||||
stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
|
||||
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_end - 1);
|
||||
liblist_cnt++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (debug) fprintf(stderr, "\n");
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
|
||||
char * buf, *start, *end;
|
||||
size_t miblen = sizeof(mib) / sizeof(mib[0]);
|
||||
size_t len;
|
||||
|
||||
if (debug) fprintf(stderr, "Library list:\n");
|
||||
if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
|
||||
|
||||
len = len * 4 / 3;
|
||||
|
||||
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (buf == MAP_FAILED) { return; }
|
||||
if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
|
||||
|
||||
munmap(buf, len);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
start = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (start < end) {
|
||||
|
||||
struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
|
||||
size_t size = region->kve_structsize;
|
||||
|
||||
if (size == 0) { break; }
|
||||
|
||||
if ((region->kve_protection & KVME_PROT_READ) &&
|
||||
!(region->kve_protection & KVME_PROT_EXEC)) {
|
||||
|
||||
liblist[liblist_cnt].name =
|
||||
region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
|
||||
liblist[liblist_cnt].addr_start = region->kve_start;
|
||||
liblist[liblist_cnt].addr_end = region->kve_end;
|
||||
|
||||
if (debug) {
|
||||
|
||||
fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
|
||||
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_end - 1);
|
||||
|
||||
}
|
||||
|
||||
liblist_cnt++;
|
||||
|
||||
}
|
||||
|
||||
start += size;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
library_list_t *find_library(char *name) {
|
||||
|
||||
char *filename = rindex(name, '/');
|
||||
|
||||
if (filename)
|
||||
filename++;
|
||||
else
|
||||
filename = name;
|
||||
|
||||
#if defined(__linux__)
|
||||
u32 i;
|
||||
for (i = 0; i < liblist_cnt; i++)
|
||||
if (strcmp(liblist[i].name, filename) == 0) return &liblist[i];
|
||||
#elif defined(__APPLE__) && defined(__LP64__)
|
||||
kern_return_t err;
|
||||
static library_list_t lib;
|
||||
|
||||
// get the list of all loaded modules from dyld
|
||||
// the task_info mach API will get the address of the dyld all_image_info
|
||||
// struct for the given task from which we can get the names and load
|
||||
// addresses of all modules
|
||||
task_dyld_info_data_t task_dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
err = task_info(mach_task_self(), TASK_DYLD_INFO,
|
||||
(task_info_t)&task_dyld_info, &count);
|
||||
|
||||
const struct dyld_all_image_infos *all_image_infos =
|
||||
(const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
|
||||
const struct dyld_image_info *image_infos = all_image_infos->infoArray;
|
||||
|
||||
for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
|
||||
|
||||
const char * image_name = image_infos[i].imageFilePath;
|
||||
mach_vm_address_t image_load_address =
|
||||
(mach_vm_address_t)image_infos[i].imageLoadAddress;
|
||||
if (strstr(image_name, name)) {
|
||||
|
||||
lib.name = name;
|
||||
lib.addr_start = (u64)image_load_address;
|
||||
lib.addr_end = 0;
|
||||
return &lib;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void gum_fake_event_sink_process(GumEventSink * sink,
|
||||
const GumEvent *ev) {
|
||||
|
||||
}
|
||||
|
||||
/* Because this CAN be called more than once, it will return the LAST range */
|
||||
static int enumerate_ranges(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GumMemoryRange *code_range = (GumMemoryRange *)user_data;
|
||||
memcpy(code_range, details->range, sizeof(*code_range));
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
#ifndef __APPLE__
|
||||
(void)personality(ADDR_NO_RANDOMIZE); // disable ASLR
|
||||
#endif
|
||||
|
||||
// STEP 2: load the library you want to fuzz and lookup the functions,
|
||||
// inclusive of the cleanup functions.
|
||||
// If there is just one function, then there is nothing to change
|
||||
// or add here.
|
||||
|
||||
void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY);
|
||||
if (!dl) {
|
||||
|
||||
fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
if (!(o_function = dlsym(dl, TARGET_FUNCTION))) {
|
||||
|
||||
fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
// END STEP 2
|
||||
|
||||
read_library_information();
|
||||
library_list_t *lib = find_library(TARGET_LIBRARY);
|
||||
|
||||
if (lib == NULL) {
|
||||
|
||||
fprintf(stderr, "Could not find target library\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
gum_init_embedded();
|
||||
if (!gum_stalker_is_supported()) {
|
||||
|
||||
gum_deinit_embedded();
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
GumStalker *stalker = gum_stalker_new();
|
||||
|
||||
/*
|
||||
This does not work here as we load a shared library. pretty sure this
|
||||
would also be easily solvable with frida gum, but I already have all the
|
||||
code I need from afl-untracer
|
||||
|
||||
GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY);
|
||||
GumMemoryRange code_range;
|
||||
gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges,
|
||||
&code_range);
|
||||
guint64 code_start = code_range.base_address - base_address;
|
||||
guint64 code_end = (code_range.base_address + code_range.size) - base_address;
|
||||
range_t instr_range = {base_address, code_start, code_end};
|
||||
*/
|
||||
range_t instr_range = {0, lib->addr_start, lib->addr_end};
|
||||
|
||||
GumStalkerTransformer *transformer =
|
||||
gum_stalker_transformer_make_from_callback(instr_basic_block,
|
||||
&instr_range, NULL);
|
||||
|
||||
GumEventSink *event_sink = gum_fake_event_sink_new();
|
||||
|
||||
// to ensure that the signatures are not optimized out
|
||||
memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1);
|
||||
memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR,
|
||||
sizeof(AFL_DEFER_FORKSVR) + 1);
|
||||
__afl_manual_init();
|
||||
|
||||
//
|
||||
// any expensive target library initialization that has to be done just once
|
||||
// - put that here
|
||||
//
|
||||
|
||||
gum_stalker_follow_me(stalker, transformer, event_sink);
|
||||
|
||||
while (__afl_persistent_loop(UINT32_MAX) != 0) {
|
||||
|
||||
previous_pc = 0; // Required!
|
||||
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "CLIENT crc: %016llx len: %u\n", hash64(__afl_fuzz_ptr, *__a
|
||||
fprintf(stderr, "RECV:");
|
||||
for (int i = 0; i < *__afl_fuzz_len; i++)
|
||||
fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
|
||||
fprintf(stderr,"\n");
|
||||
#endif
|
||||
|
||||
// STEP 3: ensure the minimum length is present and setup the target
|
||||
// function to fuzz.
|
||||
|
||||
if (*__afl_fuzz_len > 0) {
|
||||
|
||||
__afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate
|
||||
(*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len);
|
||||
|
||||
}
|
||||
|
||||
// END STEP 3
|
||||
|
||||
}
|
||||
|
||||
gum_stalker_unfollow_me(stalker);
|
||||
|
||||
while (gum_stalker_garbage_collect(stalker))
|
||||
g_usleep(10000);
|
||||
|
||||
g_object_unref(stalker);
|
||||
g_object_unref(transformer);
|
||||
g_object_unref(event_sink);
|
||||
gum_deinit_embedded();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
53
examples/afl_frida/afl-frida.h
Normal file
53
examples/afl_frida/afl-frida.h
Normal file
@ -0,0 +1,53 @@
|
||||
extern int is_persistent;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM,
|
||||
FAKE_EVENT_SINK, GObject)
|
||||
|
||||
struct _GumFakeEventSink {
|
||||
|
||||
GObject parent;
|
||||
GumEventType mask;
|
||||
|
||||
};
|
||||
|
||||
GumEventSink *gum_fake_event_sink_new(void);
|
||||
void gum_fake_event_sink_reset(GumFakeEventSink *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
typedef struct {
|
||||
|
||||
GumAddress base_address;
|
||||
guint64 code_start, code_end;
|
||||
|
||||
} range_t;
|
||||
|
||||
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
|
||||
gpointer user_data);
|
||||
#pragma once
|
||||
|
||||
void afl_setup(void);
|
||||
void afl_start_forkserver(void);
|
||||
int __afl_persistent_loop(unsigned int max_cnt);
|
||||
|
||||
inline static inline void afl_maybe_log(guint64 current_pc) {
|
||||
|
||||
extern unsigned int afl_instr_rms;
|
||||
extern uint8_t * afl_area_ptr;
|
||||
|
||||
static __thread guint64 previous_pc;
|
||||
|
||||
current_pc = (current_pc >> 4) ^ (current_pc << 8);
|
||||
current_pc &= MAP_SIZE - 1;
|
||||
|
||||
if (current_pc >= afl_instr_rms) return;
|
||||
|
||||
afl_area_ptr[current_pc ^ previous_pc]++;
|
||||
previous_pc = current_pc >> 1;
|
||||
|
||||
}
|
||||
|
35
examples/afl_frida/libtestinstr.c
Normal file
35
examples/afl_frida/libtestinstr.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
american fuzzy lop++ - a trivial program to test the build
|
||||
--------------------------------------------------------
|
||||
Originally written by Michal Zalewski
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
void testinstr(char *buf, int len) {
|
||||
|
||||
if (len < 1) return;
|
||||
buf[len] = 0;
|
||||
|
||||
// we support three input cases
|
||||
if (buf[0] == '0')
|
||||
printf("Looks like a zero to me!\n");
|
||||
else if (buf[0] == '1')
|
||||
printf("Pretty sure that is a one!\n");
|
||||
else
|
||||
printf("Neither one or zero? How quaint!\n");
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,9 @@
|
||||
#include <netinet/ip6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#ifndef USEMMAP
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -32,13 +32,14 @@ To easily run the scripts without needing to run the GUI with Ghidra:
|
||||
/opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
|
||||
rm -rf /tmp/tmp$$
|
||||
```
|
||||
The file is created at `~/Desktop/patches.txt`
|
||||
|
||||
### Fuzzing
|
||||
|
||||
Example (after modifying afl-untracer.c to your needs, compiling and creating
|
||||
patches.txt):
|
||||
```
|
||||
AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
|
||||
LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
|
||||
```
|
||||
(or even remote via afl-network-proxy).
|
||||
|
||||
|
2
examples/afl_untracer/TODO
Normal file
2
examples/afl_untracer/TODO
Normal file
@ -0,0 +1,2 @@
|
||||
* add shmem fuzzing
|
||||
* add snapshot feature?
|
@ -56,6 +56,7 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/personality.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/ucontext.h>
|
||||
@ -73,6 +74,9 @@
|
||||
|
||||
// STEP 1:
|
||||
|
||||
/* here you need to specify the parameter for the target function */
|
||||
static void *(*o_function)(u8 *buf, int len);
|
||||
|
||||
/* use stdin (1) or a file on the commandline (0) */
|
||||
static u32 use_stdin = 1;
|
||||
|
||||
@ -111,10 +115,10 @@ static library_list_t liblist[MAX_LIB_COUNT];
|
||||
static u32 liblist_cnt;
|
||||
|
||||
static void sigtrap_handler(int signum, siginfo_t *si, void *context);
|
||||
static void fuzz();
|
||||
static void fuzz(void);
|
||||
|
||||
/* read the library information */
|
||||
void read_library_information() {
|
||||
void read_library_information(void) {
|
||||
|
||||
#if defined(__linux__)
|
||||
FILE *f;
|
||||
@ -280,7 +284,7 @@ library_list_t *find_library(char *name) {
|
||||
// this seems to work for clang too. nice :) requires gcc 4.4+
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
void breakpoint() {
|
||||
void breakpoint(void) {
|
||||
|
||||
if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
|
||||
|
||||
@ -395,7 +399,7 @@ static void __afl_map_shm(void) {
|
||||
}
|
||||
|
||||
/* Fork server logic. */
|
||||
static void __afl_start_forkserver(void) {
|
||||
inline static void __afl_start_forkserver(void) {
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 status = 0;
|
||||
@ -411,7 +415,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
|
||||
s32 status;
|
||||
|
||||
@ -433,11 +437,13 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "write1 %d\n", do_exit);
|
||||
|
||||
__afl_area_ptr[0] = 1; // put something in the map
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static void __afl_end_testcase(int status) {
|
||||
inline static void __afl_end_testcase(int status) {
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "write2 %d\n", do_exit);
|
||||
@ -457,7 +463,7 @@ static void __afl_end_testcase(int status) {
|
||||
((uintptr_t)addr & 0x3) * 0x10000000000))
|
||||
#endif
|
||||
|
||||
void setup_trap_instrumentation() {
|
||||
void setup_trap_instrumentation(void) {
|
||||
|
||||
library_list_t *lib_base = NULL;
|
||||
size_t lib_size = 0;
|
||||
@ -667,12 +673,11 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
|
||||
|
||||
}
|
||||
|
||||
/* here you need to specify the parameter for the target function */
|
||||
static void *(*o_function)(u8 *buf, int len);
|
||||
|
||||
/* the MAIN function */
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
(void)personality(ADDR_NO_RANDOMIZE); // disable ASLR
|
||||
|
||||
pid = getpid();
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
@ -706,6 +711,9 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
while (1) {
|
||||
|
||||
// instead of fork() we could also use the snapshot lkm or do our own mini
|
||||
// snapshot feature like in https://github.com/marcinguy/fuzzer
|
||||
// -> snapshot.c
|
||||
if ((pid = fork()) == -1) PFATAL("fork failed");
|
||||
|
||||
if (pid) {
|
||||
@ -738,7 +746,11 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
}
|
||||
|
||||
static void fuzz() {
|
||||
#ifndef _DEBUG
|
||||
inline
|
||||
#endif
|
||||
static void
|
||||
fuzz(void) {
|
||||
|
||||
// STEP 3: call the function to fuzz, also the functions you might
|
||||
// need to call to prepare the function and - important! -
|
||||
|
BIN
examples/afl_untracer/libtestinstr.so
Executable file
BIN
examples/afl_untracer/libtestinstr.so
Executable file
Binary file not shown.
@ -1,23 +1,34 @@
|
||||
libtestinstr.so:0x2000L
|
||||
0x1050L
|
||||
0x1063L
|
||||
0x106fL
|
||||
0x1078L
|
||||
0x1080L
|
||||
0x10a4L
|
||||
0x10b0L
|
||||
0x10b8L
|
||||
0x10c0L
|
||||
0x10c9L
|
||||
0x10d7L
|
||||
0x10e3L
|
||||
0x10f8L
|
||||
0x1100L
|
||||
0x1105L
|
||||
0x111aL
|
||||
0x1135L
|
||||
0x1143L
|
||||
0x114eL
|
||||
0x115cL
|
||||
0x116aL
|
||||
0x116bL
|
||||
libtestinstr.so:0x1000
|
||||
0x10
|
||||
0x12
|
||||
0x20
|
||||
0x36
|
||||
0x30
|
||||
0x40
|
||||
0x50
|
||||
0x63
|
||||
0x6f
|
||||
0x78
|
||||
0x80
|
||||
0xa4
|
||||
0xb0
|
||||
0xb8
|
||||
0x100
|
||||
0xc0
|
||||
0xc9
|
||||
0xd7
|
||||
0xe3
|
||||
0xe8
|
||||
0xf8
|
||||
0x105
|
||||
0x11a
|
||||
0x135
|
||||
0x141
|
||||
0x143
|
||||
0x14e
|
||||
0x15a
|
||||
0x15c
|
||||
0x168
|
||||
0x16a
|
||||
0x16b
|
||||
0x170
|
||||
|
@ -7,38 +7,40 @@ ifneq "" "$(LLVM_BINDIR)"
|
||||
LLVM_BINDIR := $(LLVM_BINDIR)/
|
||||
endif
|
||||
|
||||
FLAGS=-O3 -funroll-loops -g
|
||||
CFLAGS := -O3 -funroll-loops -g
|
||||
|
||||
all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
|
||||
|
||||
aflpp_driver.o: aflpp_driver.cpp
|
||||
$(LLVM_BINDIR)clang++ $(FLAGS) -stdlib=libc++ -std=c++11 -c aflpp_driver.cpp
|
||||
aflpp_driver.o: aflpp_driver.c
|
||||
$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c 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 $(FLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
|
||||
$(LLVM_BINDIR)clang++ -I../../include -D_DEBUG=\"1\" -g -stdlib=libc++ -funroll-loops -std=c++11 -c aflpp_driver.cpp
|
||||
#$(LLVM_BINDIR)clang++ -S -emit-llvm -Wno-deprecated -I../../include $(FLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
|
||||
#$(LLVM_BINDIR)clang++ -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -stdlib=libc++ -funroll-loops -std=c++11 -c aflpp_driver.cpp
|
||||
$(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
|
||||
$(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
#$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
|
||||
#$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
ar ru libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
|
||||
aflpp_qemu_driver.o: aflpp_qemu_driver.c
|
||||
$(LLVM_BINDIR)clang $(FLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
|
||||
$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c 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
|
||||
|
||||
aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c
|
||||
$(LLVM_BINDIR)clang -fPIC $(FLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c
|
||||
$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c
|
||||
|
||||
test: debug
|
||||
#clang++ -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -stdlib=libc++ -funroll-loops -std=c++11 -o aflpp_driver_test.ll aflpp_driver_test.cpp
|
||||
afl-clang-fast++ -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -stdlib=libc++ -funroll-loops -std=c++11 -o aflpp_driver_test aflpp_driver_test.cpp libAFLDriver.a
|
||||
#clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c
|
||||
afl-clang-fast -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test aflpp_driver_test.c libAFLDriver.a afl-performance.o
|
||||
|
||||
clean:
|
||||
rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test
|
||||
|
@ -14,12 +14,15 @@ cat << EOF > test_fuzzer.cc
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
if (size > 0 && data[0] == 'H')
|
||||
if (size > 1 && data[1] == 'I')
|
||||
if (size > 2 && data[2] == '!')
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
EOF
|
||||
# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
|
||||
clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
|
||||
@ -49,225 +52,247 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both.
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "config.h"
|
||||
#include "cmplog.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "hash.h"
|
||||
#include "hash.h"
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#define MAP_FIXED_NOREPLACE 0x100000
|
||||
#endif
|
||||
|
||||
#define MAX_DUMMY_SIZE 256000
|
||||
|
||||
// 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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#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"
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int *__afl_fuzz_len;
|
||||
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.
|
||||
extern "C" {
|
||||
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##";
|
||||
extern "C" int __afl_persistent_loop(unsigned int);
|
||||
static volatile char suppress_warning2 = AFL_PERSISTENT[0];
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
extern "C" void __afl_manual_init();
|
||||
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
|
||||
|
||||
// Input buffer.
|
||||
static const size_t kMaxAflInputSize = 1 << 20;
|
||||
static uint8_t AflInputBuf[kMaxAflInputSize];
|
||||
void __afl_manual_init();
|
||||
|
||||
// Use this optionally defined function to output sanitizer messages even if
|
||||
// user asks to close stderr.
|
||||
__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
|
||||
__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;
|
||||
static FILE *output_file;
|
||||
|
||||
// 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;
|
||||
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();
|
||||
if (!temp) abort();
|
||||
dup2(fileno(temp), fd);
|
||||
fclose(temp);
|
||||
|
||||
}
|
||||
|
||||
static void close_stdout() { discard_output(STDOUT_FILENO); }
|
||||
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();
|
||||
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));
|
||||
if (!new_output_file) abort();
|
||||
if (!__sanitizer_set_report_fd) return;
|
||||
__sanitizer_set_report_fd((void *)output_fd);
|
||||
discard_output(output_fileno);
|
||||
}
|
||||
|
||||
static void Printf(const char *Fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, Fmt);
|
||||
vfprintf(output_file, Fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(output_file);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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();
|
||||
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.
|
||||
extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
|
||||
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
|
||||
// assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
// Execute any files provided as parameters.
|
||||
static int ExecuteFilesOnyByOne(int argc, char **argv) {
|
||||
|
||||
unsigned char *buf = malloc(MAX_FILE);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::ifstream in(argv[i], std::ios::binary);
|
||||
in.seekg(0, in.end);
|
||||
size_t length = in.tellg();
|
||||
in.seekg (0, in.beg);
|
||||
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
|
||||
// Allocate exactly length bytes so that we reliably catch buffer overflows.
|
||||
std::vector<char> bytes(length);
|
||||
in.read(bytes.data(), bytes.size());
|
||||
assert(in);
|
||||
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
|
||||
bytes.size());
|
||||
std::cout << "Execution successful" << std::endl;
|
||||
|
||||
int fd = open(argv[i], O_RDONLY);
|
||||
if (fd == -1) continue;
|
||||
ssize_t length = read(fd, buf, MAX_FILE);
|
||||
if (length > 0) {
|
||||
|
||||
printf("Reading %zu bytes from %s\n", length, argv[i]);
|
||||
LLVMFuzzerTestOneInput(buf, length);
|
||||
printf("Execution successful.\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Printf(
|
||||
|
||||
printf(
|
||||
"======================= INFO =========================\n"
|
||||
"This binary is built for AFL-fuzz.\n"
|
||||
"This binary is built for afl++.\n"
|
||||
"To run the target function on individual input(s) execute this:\n"
|
||||
" %s < INPUT_FILE\n"
|
||||
"or\n"
|
||||
" %s INPUT_FILE1 [INPUT_FILE2 ... ]\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"
|
||||
" 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], argv[0]);
|
||||
argv[0], argv[0]);
|
||||
|
||||
output_file = stderr;
|
||||
maybe_duplicate_stderr();
|
||||
maybe_close_fd_mask();
|
||||
if (LLVMFuzzerInitialize)
|
||||
if (LLVMFuzzerInitialize) {
|
||||
|
||||
fprintf(stderr, "Running LLVMFuzzerInitialize ...\n");
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
fprintf(stderr, "continue...\n");
|
||||
|
||||
}
|
||||
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
uint8_t dummy_input[1] = {0};
|
||||
int N = 100000;
|
||||
uint8_t dummy_input[64] = {0};
|
||||
memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
|
||||
memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
|
||||
sizeof(AFL_DEFER_FORKSVR));
|
||||
int N = INT_MAX;
|
||||
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);
|
||||
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);
|
||||
else if (argc > 1) {
|
||||
// if (!getenv("AFL_DRIVER_DONT_DEFER")) {
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
__afl_manual_init();
|
||||
// }
|
||||
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
__afl_manual_init();
|
||||
return ExecuteFilesOnyByOne(argc, argv);
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
// if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
// if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
@ -276,17 +301,26 @@ int main(int argc, char **argv) {
|
||||
|
||||
int num_runs = 0;
|
||||
while (__afl_persistent_loop(N)) {
|
||||
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "CLIENT crc: %016llx len: %u\n", hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705), *__afl_fuzz_len);
|
||||
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");
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (*__afl_fuzz_len) {
|
||||
|
||||
num_runs++;
|
||||
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
|
||||
printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
|
||||
}
|
||||
|
31
examples/aflpp_driver/aflpp_driver_test.c
Normal file
31
examples/aflpp_driver/aflpp_driver_test.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
|
||||
|
||||
if (Data[0] == 'F')
|
||||
if (Data[1] == 'A')
|
||||
if (Data[2] == '$')
|
||||
if (Data[3] == '$')
|
||||
if (Data[4] == '$') abort();
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
crashme(Data, Size);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "hash.h"
|
||||
|
||||
extern "C" 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 (Data[0] == 'F')
|
||||
if (Data[1] == 'A')
|
||||
if (Data[2] == '$')
|
||||
if (Data[3] == '$')
|
||||
if (Data[4] == '$')
|
||||
abort();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
@ -83,7 +83,7 @@ typedef struct post_state {
|
||||
|
||||
} post_state_t;
|
||||
|
||||
void *afl afl_custom_init(void *afl) {
|
||||
void *afl_custom_init(void *afl) {
|
||||
|
||||
post_state_t *state = malloc(sizeof(post_state_t));
|
||||
if (!state) {
|
||||
|
64
examples/defork/Makefile
Normal file
64
examples/defork/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# american fuzzy lop++ - defork
|
||||
# ----------------------------------
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
|
||||
CFLAGS = -fPIC -Wall -Wextra
|
||||
LDFLAGS = -shared
|
||||
|
||||
UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
|
||||
UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
|
||||
|
||||
_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
# on gcc for arm there is no -m32, but -mbe32
|
||||
M32FLAG = -m32
|
||||
M64FLAG = -m64
|
||||
|
||||
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
|
||||
CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
|
||||
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
|
||||
CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
|
||||
|
||||
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
|
||||
__M32FLAG=$(_M32FLAG:00=-mbe32)
|
||||
___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
|
||||
M32FLAG=$(___M32FLAG)
|
||||
#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
# M32FLAG = -mbe32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
all: defork32.so defork64.so
|
||||
|
||||
defork32.so: defork.c
|
||||
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)"
|
||||
|
||||
defork64.so: defork.c
|
||||
-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)"
|
||||
|
||||
install: defork32.so defork64.so
|
||||
install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
|
||||
if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi
|
||||
if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi
|
||||
|
||||
target:
|
||||
../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror
|
||||
|
||||
clean:
|
||||
rm -f defork32.so defork64.so forking_target
|
11
examples/defork/README.md
Normal file
11
examples/defork/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# defork
|
||||
|
||||
when the target forks, this breaks all normal fuzzing runs.
|
||||
Sometimes, though, it is enough to just run the child process.
|
||||
If this is the case, then this LD_PRELOAD library will always return 0 on fork,
|
||||
the target will belive it is running as the child, post-fork.
|
||||
|
||||
This is defork.c from the amazing preeny project
|
||||
https://github.com/zardus/preeny
|
||||
|
||||
It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked.
|
50
examples/defork/defork.c
Normal file
50
examples/defork/defork.c
Normal file
@ -0,0 +1,50 @@
|
||||
#define __GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../../include/config.h"
|
||||
|
||||
/* we want to fork once (for the afl++ forkserver),
|
||||
then immediately return as child on subsequent forks. */
|
||||
static bool forked = 0;
|
||||
|
||||
pid_t (*original_fork)(void);
|
||||
|
||||
/* In case we are not running in afl, we use a dummy original_fork */
|
||||
static pid_t nop(void) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void preeny_fork_orig() {
|
||||
|
||||
if (getenv(SHM_ENV_VAR)) {
|
||||
|
||||
printf("defork: running in AFL++. Allowing forkserver.\n");
|
||||
original_fork = dlsym(RTLD_NEXT, "socket");
|
||||
|
||||
} else {
|
||||
|
||||
printf("defork: no AFL++ detected. Disabling fork from the start.\n");
|
||||
original_fork = &nop;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pid_t fork(void) {
|
||||
|
||||
/* If we forked before, or if we're in the child (pid==0),
|
||||
we don't want to fork anymore, else, we are still in the forkserver.
|
||||
The forkserver parent needs to fork infinite times, each child should never
|
||||
fork again. This can be written without branches and I hate myself for it.
|
||||
*/
|
||||
pid_t ret = !forked && original_fork();
|
||||
forked = !ret;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
48
examples/defork/forking_target.c
Normal file
48
examples/defork/forking_target.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* This is an example target for defork.c - fuzz using
|
||||
```
|
||||
mkdir in; echo a > ./in/a
|
||||
AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@
|
||||
```
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
if (argc < 2) {
|
||||
|
||||
printf("Example tool to test defork.\nUsage ./forking_target <input>\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
|
||||
printf("We're in the child.\n");
|
||||
FILE *f = fopen(argv[1], "r");
|
||||
char buf[4096];
|
||||
fread(buf, 1, 4096, f);
|
||||
uint32_t offset = buf[100] + (buf[101] << 8);
|
||||
char test_val = buf[offset];
|
||||
return test_val < 100;
|
||||
|
||||
} else if (pid < 0) {
|
||||
|
||||
perror("fork");
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
|
||||
printf("We are in the parent - defork didn't work! :( (pid=%d)\n",
|
||||
(int)pid);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,20 @@
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
/* this lets the source compile without afl-clang-fast/lto */
|
||||
#ifndef __AFL_FUZZ_TESTCASE_LEN
|
||||
|
||||
ssize_t fuzz_len;
|
||||
unsigned char fuzz_buf[1024000];
|
||||
|
||||
#define __AFL_FUZZ_TESTCASE_LEN fuzz_len
|
||||
#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
|
||||
#define __AFL_FUZZ_INIT() void sync(void);
|
||||
#define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ?
|
||||
#define __AFL_INIT() sync()
|
||||
|
||||
#endif
|
||||
|
||||
__AFL_FUZZ_INIT();
|
||||
|
||||
/* Main entry point. */
|
||||
|
@ -70,9 +70,16 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname -s)" "Haiku"
|
||||
LDFLAGS += -lrt
|
||||
LDFLAGS += -lrt
|
||||
else
|
||||
CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "SunOS"
|
||||
PLUGIN_FLAGS += -I/usr/include/gmp
|
||||
endif
|
||||
|
||||
|
||||
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
|
||||
|
||||
|
||||
@ -156,7 +163,7 @@ install: all
|
||||
install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH)
|
||||
install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
install -m 644 -T README.instrument_file.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md
|
||||
install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
|
@ -152,7 +152,7 @@ install: all
|
||||
install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH)
|
||||
install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
install -m 644 -T README.instrument_file.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md
|
||||
install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
|
@ -379,7 +379,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
u32 map_size = atoi(ptr);
|
||||
if (map_size != MAP_SIZE)
|
||||
FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast");
|
||||
WARNF("AFL_MAP_SIZE is not supported by afl-gcc-fast");
|
||||
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,11 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#include <kernel/OS.h>
|
||||
#include <kernel/scheduler.h>
|
||||
#endif
|
||||
|
||||
/* For systems that have sched_setaffinity; right now just Linux, but one
|
||||
can hope... */
|
||||
|
||||
@ -139,7 +144,8 @@ struct queue_entry {
|
||||
var_behavior, /* Variable behavior? */
|
||||
favored, /* Currently favored? */
|
||||
fs_redundant, /* Marked as redundant in the fs? */
|
||||
fully_colorized; /* Do not run redqueen stage again */
|
||||
fully_colorized, /* Do not run redqueen stage again */
|
||||
is_ascii; /* Is the input just ascii text? */
|
||||
|
||||
u32 bitmap_size, /* Number of bits set in bitmap */
|
||||
fuzz_level; /* Number of fuzzing iterations */
|
||||
@ -166,6 +172,14 @@ struct extra_data {
|
||||
|
||||
};
|
||||
|
||||
struct auto_extra_data {
|
||||
|
||||
u8 data[MAX_AUTO_EXTRA]; /* Dictionary token data */
|
||||
u32 len; /* Dictionary token length */
|
||||
u32 hit_cnt; /* Use count in the corpus */
|
||||
|
||||
};
|
||||
|
||||
/* Fuzzing stages */
|
||||
|
||||
enum {
|
||||
@ -333,7 +347,7 @@ typedef struct afl_env_vars {
|
||||
afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
|
||||
afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
|
||||
afl_bench_until_crash, afl_debug_child_output, afl_autoresume,
|
||||
afl_cal_fast;
|
||||
afl_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;
|
||||
@ -347,6 +361,13 @@ struct afl_pass_stat {
|
||||
|
||||
};
|
||||
|
||||
struct foreign_sync {
|
||||
|
||||
u8 * dir;
|
||||
time_t ctime;
|
||||
|
||||
};
|
||||
|
||||
typedef struct afl_state {
|
||||
|
||||
/* Position of this state in the global states list */
|
||||
@ -454,7 +475,9 @@ typedef struct afl_state {
|
||||
fixed_seed, /* do not reseed */
|
||||
fast_cal, /* Try to calibrate faster? */
|
||||
disable_trim, /* Never trim in fuzz_one */
|
||||
shmem_testcase_mode; /* If sharedmem testcases are used */
|
||||
shmem_testcase_mode, /* If sharedmem testcases are used */
|
||||
expand_havoc, /* perform expensive havoc after no find */
|
||||
cycle_schedules; /* cycle power schedules ? */
|
||||
|
||||
u8 *virgin_bits, /* Regions yet untouched by fuzzing */
|
||||
*virgin_tmout, /* Bits we haven't seen in tmouts */
|
||||
@ -535,7 +558,8 @@ typedef struct afl_state {
|
||||
u64 total_bitmap_size, /* Total bit count for all bitmaps */
|
||||
total_bitmap_entries; /* Number of bitmaps counted */
|
||||
|
||||
s32 cpu_core_count; /* CPU core count */
|
||||
s32 cpu_core_count, /* CPU core count */
|
||||
cpu_to_bind; /* bind to specific CPU */
|
||||
|
||||
#ifdef HAVE_AFFINITY
|
||||
s32 cpu_aff; /* Selected CPU core */
|
||||
@ -546,13 +570,18 @@ typedef struct afl_state {
|
||||
*queue_top, /* Top of the list */
|
||||
*q_prev100; /* Previous 100 marker */
|
||||
|
||||
// growing buf
|
||||
struct queue_entry **queue_buf;
|
||||
size_t queue_size;
|
||||
|
||||
struct queue_entry **top_rated; /* Top entries for bitmap bytes */
|
||||
|
||||
struct extra_data *extras; /* Extra tokens to fuzz with */
|
||||
u32 extras_cnt; /* Total number of tokens read */
|
||||
|
||||
struct extra_data *a_extras; /* Automatically selected extras */
|
||||
u32 a_extras_cnt; /* Total number of tokens available */
|
||||
struct auto_extra_data
|
||||
a_extras[MAX_AUTO_EXTRAS]; /* Automatically selected extras */
|
||||
u32 a_extras_cnt; /* Total number of tokens available */
|
||||
|
||||
/* afl_postprocess API - Now supported via custom mutators */
|
||||
|
||||
@ -574,13 +603,20 @@ typedef struct afl_state {
|
||||
u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
|
||||
up to 256 */
|
||||
|
||||
unsigned long long int last_avg_exec_update;
|
||||
u32 last_avg_execs;
|
||||
float last_avg_execs_saved;
|
||||
|
||||
/* foreign sync */
|
||||
#define FOREIGN_SYNCS_MAX 32
|
||||
u8 foreign_sync_cnt;
|
||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||
|
||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||
u8 do_document;
|
||||
u32 document_counter;
|
||||
#endif
|
||||
|
||||
void *maybe_add_auto;
|
||||
|
||||
/* statistics file */
|
||||
double last_bitmap_cvg, last_stability, last_eps;
|
||||
|
||||
@ -627,6 +663,7 @@ typedef struct afl_state {
|
||||
struct custom_mutator {
|
||||
|
||||
const char *name;
|
||||
char * name_short;
|
||||
void * dh;
|
||||
u8 * post_process_buf;
|
||||
size_t post_process_size;
|
||||
@ -881,7 +918,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 maybe_add_auto(void *, u8 *, u32);
|
||||
void maybe_add_auto(afl_state_t *, u8 *, u32);
|
||||
void save_auto(afl_state_t *);
|
||||
void load_auto(afl_state_t *);
|
||||
void destroy_extras(afl_state_t *);
|
||||
@ -937,6 +974,7 @@ void fix_up_banner(afl_state_t *, u8 *);
|
||||
void check_if_tty(afl_state_t *);
|
||||
void setup_signal_handlers(void);
|
||||
void save_cmdline(afl_state_t *, u32, char **);
|
||||
void read_foreign_testcases(afl_state_t *, int);
|
||||
|
||||
/* CmpLog */
|
||||
|
||||
@ -956,6 +994,8 @@ uint64_t rand_next(afl_state_t *afl);
|
||||
|
||||
static inline u32 rand_below(afl_state_t *afl, u32 limit) {
|
||||
|
||||
if (limit <= 1) return 0;
|
||||
|
||||
/* The boundary not being necessarily a power of 2,
|
||||
we need to ensure the result uniformity. */
|
||||
if (unlikely(!afl->rand_cnt--) && likely(!afl->fixed_seed)) {
|
||||
@ -971,6 +1011,32 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
|
||||
|
||||
}
|
||||
|
||||
/* we prefer lower range values here */
|
||||
/* this is only called with normal havoc, not MOpt, to have an equalizer for
|
||||
expand havoc mode */
|
||||
static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) {
|
||||
|
||||
if (limit <= 1) return 0;
|
||||
|
||||
switch (rand_below(afl, 3)) {
|
||||
|
||||
case 2:
|
||||
return (rand_below(afl, limit) % (1 + rand_below(afl, limit - 1))) %
|
||||
(1 + rand_below(afl, limit - 1));
|
||||
break;
|
||||
case 1:
|
||||
return rand_below(afl, limit) % (1 + rand_below(afl, limit - 1));
|
||||
break;
|
||||
case 0:
|
||||
return rand_below(afl, limit);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 1; // cannot be reached
|
||||
|
||||
}
|
||||
|
||||
static inline s64 rand_get_seed(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(afl->fixed_seed)) { return afl->init_seed; }
|
||||
|
@ -175,43 +175,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
return (u8 *)memcpy(ret, str, size);
|
||||
|
||||
}
|
||||
|
||||
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
||||
or NULL inputs. */
|
||||
|
||||
static inline void *DFL_ck_memdup(void *mem, u32 size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (!mem || !size) { return NULL; }
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
return memcpy(ret, mem, size);
|
||||
|
||||
}
|
||||
|
||||
/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
||||
Returns NULL for zero-sized or NULL inputs. */
|
||||
|
||||
static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
|
||||
u8 *ret;
|
||||
|
||||
if (!mem || !size) { return NULL; }
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = (u8 *)malloc(size + 1);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
memcpy(ret, mem, size);
|
||||
ret[size] = 0;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above
|
||||
@ -222,8 +185,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
@ -487,55 +448,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
return memcpy(ret, str, size);
|
||||
|
||||
}
|
||||
|
||||
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
||||
or NULL inputs. */
|
||||
|
||||
static inline void *DFL_ck_memdup(void *mem, u32 size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
return memcpy(ret, mem, size);
|
||||
|
||||
}
|
||||
|
||||
/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
||||
Returns NULL for zero-sized or NULL inputs. */
|
||||
|
||||
static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
|
||||
u8 *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL + 1);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
memcpy(ret, mem, size);
|
||||
ret[size] = 0;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
@ -548,8 +460,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
@ -713,24 +623,6 @@ static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
|
||||
|
||||
}
|
||||
|
||||
static inline void *TRK_ck_memdup(void *mem, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void *ret = DFL_ck_memdup(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void *TRK_ck_memdup_str(void *mem, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void *ret = DFL_ck_memdup_str(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
@ -754,12 +646,6 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
|
||||
|
||||
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup(_p1, _p2) \
|
||||
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup_str(_p1, _p2) \
|
||||
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
@ -28,7 +28,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++2.66c"
|
||||
#define VERSION "++2.67c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -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): */
|
||||
@ -380,6 +380,10 @@
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
|
||||
/* Uncomment this to use inferior block-coverage-based instrumentation. Note
|
||||
that you need to recompile the target binary for this to have any effect: */
|
||||
|
||||
@ -397,5 +401,28 @@
|
||||
|
||||
// #define IGNORE_FINDS
|
||||
|
||||
/* Text mutations */
|
||||
|
||||
/* Minimum length of a queue input to be evaluated for "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_LEN 12
|
||||
|
||||
/* What is the minimum percentage of ascii characters present to be classifed
|
||||
as "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_PERCENT 94
|
||||
|
||||
/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */
|
||||
|
||||
#define AFL_TXT_BIAS 6
|
||||
|
||||
/* Maximum length of a string to tamper with */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_LEN 1024
|
||||
|
||||
/* Maximum mutations on a string */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_MUTATIONS 6
|
||||
|
||||
#endif /* ! _HAVE_CONFIG_H */
|
||||
|
||||
|
@ -28,11 +28,6 @@
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
|
||||
/* __FUNCTION__ is non-iso */
|
||||
#ifdef __func__
|
||||
#define __FUNCTION__ __func__
|
||||
#endif
|
||||
|
||||
/*******************
|
||||
* Terminal colors *
|
||||
*******************/
|
||||
@ -223,43 +218,43 @@
|
||||
|
||||
/* Die with a verbose non-OS fatal error message. */
|
||||
|
||||
#define FATAL(x...) \
|
||||
do { \
|
||||
\
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \
|
||||
__FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
\
|
||||
#define FATAL(x...) \
|
||||
do { \
|
||||
\
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Die by calling abort() to provide a core dump. */
|
||||
|
||||
#define ABORT(x...) \
|
||||
do { \
|
||||
\
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \
|
||||
__FILE__, __LINE__); \
|
||||
abort(); \
|
||||
\
|
||||
#define ABORT(x...) \
|
||||
do { \
|
||||
\
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
abort(); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Die while also including the output of perror(). */
|
||||
|
||||
#define PFATAL(x...) \
|
||||
do { \
|
||||
\
|
||||
fflush(stdout); \
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] SYSTEM ERROR : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __FUNCTION__, \
|
||||
__FILE__, __LINE__); \
|
||||
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
|
||||
exit(1); \
|
||||
\
|
||||
#define PFATAL(x...) \
|
||||
do { \
|
||||
\
|
||||
fflush(stdout); \
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] SYSTEM ERROR : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
|
||||
exit(1); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Die with FATAL() or PFATAL() depending on the value of res (used to
|
||||
@ -281,7 +276,7 @@
|
||||
#define ck_write(fd, buf, len, fn) \
|
||||
do { \
|
||||
\
|
||||
u32 _len = (len); \
|
||||
s32 _len = (s32)(len); \
|
||||
s32 _res = write(fd, buf, _len); \
|
||||
if (_res != _len) RPFATAL(_res, "Short write to %s", fn); \
|
||||
\
|
||||
@ -290,7 +285,7 @@
|
||||
#define ck_read(fd, buf, len, fn) \
|
||||
do { \
|
||||
\
|
||||
u32 _len = (len); \
|
||||
s32 _len = (s32)(len); \
|
||||
s32 _res = read(fd, buf, _len); \
|
||||
if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
|
||||
\
|
||||
|
@ -34,6 +34,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"AFL_CXX",
|
||||
"AFL_CYCLE_SCHEDULES",
|
||||
"AFL_DEBUG",
|
||||
"AFL_DEBUG_CHILD_OUTPUT",
|
||||
"AFL_DEBUG_GDB",
|
||||
@ -61,9 +62,13 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_REAL_LD",
|
||||
"AFL_LD_PRELOAD",
|
||||
"AFL_LD_VERBOSE",
|
||||
"AFL_LLVM_ALLOWLIST",
|
||||
"AFL_LLVM_DENYLIST",
|
||||
"AFL_LLVM_BLOCKLIST",
|
||||
"AFL_LLVM_CMPLOG",
|
||||
"AFL_LLVM_INSTRIM",
|
||||
"AFL_LLVM_CTX",
|
||||
"AFL_LLVM_DOCUMENT_IDS",
|
||||
"AFL_LLVM_INSTRUMENT",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
"AFL_LLVM_LTO_AUTODICTIONARY",
|
||||
@ -129,6 +134,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_USE_CFISAN",
|
||||
"AFL_WINE_PATH",
|
||||
"AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW",
|
||||
NULL
|
||||
|
||||
};
|
||||
|
@ -89,9 +89,9 @@ typedef struct afl_forkserver {
|
||||
/* Function to kick off the forkserver child */
|
||||
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
u8 *function_opt; /* for autodictionary: afl ptr */
|
||||
u8 *afl_ptr; /* for autodictionary: afl ptr */
|
||||
|
||||
void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len);
|
||||
void (*autodict_func)(void *afl_ptr, u8 *mem, u32 len);
|
||||
|
||||
} afl_forkserver_t;
|
||||
|
||||
|
@ -25,8 +25,7 @@
|
||||
// From AFL-Snapshot-LKM/include/afl_snapshot.h (must be kept synced)
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define AFL_SNAPSHOT_FILE_NAME "/dev/afl_snapshot"
|
||||
@ -35,6 +34,35 @@
|
||||
|
||||
#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1)
|
||||
#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2)
|
||||
#define AFL_SNAPSHOT_EXCLUDE_VMRANGE \
|
||||
_IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 3, struct afl_snapshot_vmrange_args *)
|
||||
#define AFL_SNAPSHOT_INCLUDE_VMRANGE \
|
||||
_IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 4, struct afl_snapshot_vmrange_args *)
|
||||
#define AFL_SNAPSHOT_IOCTL_TAKE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 5, int)
|
||||
#define AFL_SNAPSHOT_IOCTL_RESTORE _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 6)
|
||||
|
||||
// Trace new mmaped ares and unmap them on restore.
|
||||
#define AFL_SNAPSHOT_MMAP 1
|
||||
// Do not snapshot any page (by default all writeable not-shared pages
|
||||
// are shanpshotted.
|
||||
#define AFL_SNAPSHOT_BLOCK 2
|
||||
// Snapshot file descriptor state, close newly opened descriptors
|
||||
#define AFL_SNAPSHOT_FDS 4
|
||||
// Snapshot registers state
|
||||
#define AFL_SNAPSHOT_REGS 8
|
||||
// Perform a restore when exit_group is invoked
|
||||
#define AFL_SNAPSHOT_EXIT 16
|
||||
// TODO(andrea) allow not COW snapshots (high perf on small processes)
|
||||
// Disable COW, restore all the snapshotted pages
|
||||
#define AFL_SNAPSHOT_NOCOW 32
|
||||
// Do not snapshot Stack pages
|
||||
#define AFL_SNAPSHOT_NOSTACK 64
|
||||
|
||||
struct afl_snapshot_vmrange_args {
|
||||
|
||||
unsigned long start, end;
|
||||
|
||||
};
|
||||
|
||||
static int afl_snapshot_dev_fd;
|
||||
|
||||
@ -45,15 +73,43 @@ static int afl_snapshot_init(void) {
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_do() {
|
||||
static void afl_snapshot_exclude_vmrange(void *start, void *end) {
|
||||
|
||||
struct afl_snapshot_vmrange_args args = {(unsigned long)start,
|
||||
(unsigned long)end};
|
||||
ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_EXCLUDE_VMRANGE, &args);
|
||||
|
||||
}
|
||||
|
||||
static void afl_snapshot_include_vmrange(void *start, void *end) {
|
||||
|
||||
struct afl_snapshot_vmrange_args args = {(unsigned long)start,
|
||||
(unsigned long)end};
|
||||
ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_INCLUDE_VMRANGE, &args);
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_take(int config) {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_TAKE, config);
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_do(void) {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO);
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_clean(void) {
|
||||
static void afl_snapshot_restore(void) {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN);
|
||||
ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_RESTORE);
|
||||
|
||||
}
|
||||
|
||||
static void afl_snapshot_clean(void) {
|
||||
|
||||
ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN);
|
||||
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ static u32 alloc_canary;
|
||||
|
||||
static void *__dislocator_alloc(size_t len) {
|
||||
|
||||
u8 * ret;
|
||||
u8 * ret, *base;
|
||||
size_t tlen;
|
||||
int flags, fd, sp;
|
||||
|
||||
@ -189,6 +189,7 @@ static void *__dislocator_alloc(size_t len) {
|
||||
/* We will also store buffer length and a canary below the actual buffer, so
|
||||
let's add 8 bytes for that. */
|
||||
|
||||
base = NULL;
|
||||
tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
fd = -1;
|
||||
@ -201,12 +202,20 @@ static void *__dislocator_alloc(size_t len) {
|
||||
if (sp) flags |= MAP_HUGETLB;
|
||||
#elif defined(__FreeBSD__)
|
||||
if (sp) flags |= MAP_ALIGNED_SUPER;
|
||||
#elif defined(__sun)
|
||||
if (sp) {
|
||||
|
||||
base = (void *)(caddr_t)(1 << 21);
|
||||
flags |= MAP_ALIGN;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
(void)sp;
|
||||
#endif
|
||||
|
||||
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
ret = (u8 *)mmap(base, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
#if defined(USEHUGEPAGE)
|
||||
/* We try one more time with regular call */
|
||||
if (ret == MAP_FAILED) {
|
||||
@ -217,6 +226,8 @@ static void *__dislocator_alloc(size_t len) {
|
||||
flags &= -MAP_HUGETLB;
|
||||
#elif defined(__FreeBSD__)
|
||||
flags &= -MAP_ALIGNED_SUPER;
|
||||
#elif defined(__sun)
|
||||
flags &= -MAP_ALIGN;
|
||||
#endif
|
||||
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
|
||||
|
@ -28,22 +28,22 @@ UNAME_S =$(shell uname -s)# GNU make
|
||||
UNAME_S:sh=uname -s # BSD make
|
||||
_UNIQ=_QINU_
|
||||
|
||||
_OS_DL = $(_UNIQ)$(UNAME_S)
|
||||
__OS_DL = $(_OS_DL:$(_UNIQ)Linux=$(_UNIQ))
|
||||
___OS_DL = $(__OS_DL:$(_UNIQ)Darwin=$(_UNIQ))
|
||||
____OS_DL = $(___OS_DL:$(_UNIQ)DragonFly=$(_UNIQ))
|
||||
_____OS_DL = $(____OS_DL:$(_UNIQ)$(UNAME_S)=)
|
||||
______OS_DL = $(_____OS_DL:$(_UNIQ)="-ldl")
|
||||
_OS_DL = $(_UNIQ)$(UNAME_S)
|
||||
__OS_DL = $(_OS_DL:$(_UNIQ)Linux=$(_UNIQ))
|
||||
___OS_DL = $(__OS_DL:$(_UNIQ)Darwin=$(_UNIQ))
|
||||
____OS_DL = $(___OS_DL:$(_UNIQ)$(UNAME_S)=)
|
||||
_____OS_DL = $(____OS_DL:$(_UNIQ)="-ldl")
|
||||
|
||||
_OS_TARGET = $(____OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
|
||||
__OS_TARGET = $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
|
||||
___OS_TARGET = $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
|
||||
____OS_TARGET = $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
|
||||
_____OS_TARGET = $(___OS_TARGET:$(_UNIQ)$(UNAME_S)=)
|
||||
_OS_TARGET = $(___OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
|
||||
__OS_TARGET = $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
|
||||
___OS_TARGET = $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
|
||||
____OS_TARGET = $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
|
||||
_____OS_TARGET = $(____OS_TARGET:$(_UNIQ)SunOS=$(_UNIQ))
|
||||
______OS_TARGET = $(_____OS_TARGET:$(_UNIQ)$(UNAME_S)=)
|
||||
|
||||
TARGETS = $(____OS_TARGET:$(_UNIQ)=libtokencap.so)
|
||||
TARGETS = $(______OS_TARGET:$(_UNIQ)=libtokencap.so)
|
||||
|
||||
LDFLAGS += $(______OS_DL)
|
||||
LDFLAGS += $(_____OS_DL)
|
||||
|
||||
#ifeq "$(shell uname)" "Linux"
|
||||
# TARGETS = libtokencap.so
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && \
|
||||
!defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__ && \
|
||||
!defined(__HAIKU__)
|
||||
!defined(__HAIKU__) && !defined(__sun)
|
||||
#error "Sorry, this library is unsupported in this platform for now!"
|
||||
#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
|
||||
!__NetBSD__*/
|
||||
@ -52,6 +52,10 @@
|
||||
#include <sys/mman.h>
|
||||
#elif defined __HAIKU__
|
||||
#include <kernel/image.h>
|
||||
#elif defined __sun
|
||||
/* For map addresses the old struct is enough */
|
||||
#include <sys/procfs.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
@ -237,6 +241,8 @@ static void __tokencap_load_mappings(void) {
|
||||
image_info ii;
|
||||
int32_t group = 0;
|
||||
|
||||
__tokencap_ro_loaded = 1;
|
||||
|
||||
while (get_next_image_info(0, &group, &ii) == B_OK) {
|
||||
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = ii.text;
|
||||
@ -246,6 +252,38 @@ static void __tokencap_load_mappings(void) {
|
||||
|
||||
}
|
||||
|
||||
#elif defined __sun
|
||||
prmap_t *c, *map;
|
||||
char path[PATH_MAX];
|
||||
ssize_t r;
|
||||
size_t hint;
|
||||
int fd;
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%ld/map", getpid());
|
||||
fd = open(path, O_RDONLY);
|
||||
hint = (1 << 20);
|
||||
map = malloc(hint);
|
||||
|
||||
__tokencap_ro_loaded = 1;
|
||||
|
||||
for (; (r = pread(fd, map, hint, 0)) == hint;) {
|
||||
|
||||
hint <<= 1;
|
||||
map = realloc(map, hint);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
|
||||
|
||||
}
|
||||
|
||||
free(map);
|
||||
close(fd);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -32,15 +32,16 @@ ifeq "$(shell uname)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
ifeq "$(HAS_OPT)" "1"
|
||||
$(error llvm_mode needs a complete llvm installation (versions 3.4 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
$(error llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^19' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
|
||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||
@ -53,20 +54,29 @@ ifeq "$(LLVMVER)" ""
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.4 up to 11)
|
||||
$(warning llvm_mode only supports llvm versions 3.4 up to 12)
|
||||
endif
|
||||
|
||||
LLVM_TOO_OLD=1
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
LLVM_TOO_OLD=0
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
LLVM_STDCXX = c++14
|
||||
LLVM_TOO_OLD=0
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "11"
|
||||
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
|
||||
ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
|
||||
$(shell sleep 1)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
#TEST_MMAP = 1
|
||||
endif
|
||||
@ -182,18 +192,27 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
||||
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
||||
else
|
||||
$(warn ld.lld not found, can not enable LTO mode)
|
||||
$(warn ld.lld not found, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
else
|
||||
$(warn clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
AFL_CLANG_FUSELD=
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FUSELD=1
|
||||
endif
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FUSELD=1
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_LDPATH=1
|
||||
endif
|
||||
else
|
||||
$(warn -fuse-ld is not working, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
|
||||
@ -202,7 +221,9 @@ CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
|
||||
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
|
||||
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
|
||||
-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
|
||||
override CFLAGS += $(CFLAGS_SAFE)
|
||||
|
||||
@ -220,7 +241,7 @@ endif
|
||||
ifneq "$(LLVM_CONFIG)" ""
|
||||
CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
|
||||
endif
|
||||
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS)
|
||||
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
@ -371,20 +392,20 @@ endif
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
|
||||
document:
|
||||
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
|
||||
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) -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) -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) $(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
|
||||
|
||||
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
|
||||
$(CLANG_BIN) $(CFLAGS_SAFE) -O3 -Wno-unused-result -fPIC -c $< -o $@
|
||||
$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -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) $(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) -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) $(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) -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..."
|
||||
@ -411,6 +432,7 @@ 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
|
||||
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
|
||||
install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md
|
||||
|
@ -56,7 +56,6 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
protected:
|
||||
uint32_t function_minimum_size = 1;
|
||||
uint32_t debug = 0;
|
||||
char * skip_nozero = NULL;
|
||||
|
||||
private:
|
||||
@ -95,14 +94,13 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
#if LLVM_VERSION_MAJOR > 4 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
|
||||
char be_quiet = 0;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
@ -146,7 +144,7 @@ struct InsTrim : public ModulePass {
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
unsigned int ngram_size = 0;
|
||||
/* Decide previous location vector size (must be a power of two) */
|
||||
VectorType *PrevLocTy;
|
||||
VectorType *PrevLocTy = NULL;
|
||||
|
||||
if (ngram_size_str)
|
||||
if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
|
||||
@ -196,7 +194,7 @@ struct InsTrim : public ModulePass {
|
||||
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
|
||||
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
|
||||
GlobalVariable *AFLPrevLoc;
|
||||
GlobalVariable *AFLContext;
|
||||
GlobalVariable *AFLContext = NULL;
|
||||
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
|
||||
|
||||
if (ctx_str)
|
||||
@ -258,6 +256,8 @@ struct InsTrim : public ModulePass {
|
||||
u64 total_rs = 0;
|
||||
u64 total_hs = 0;
|
||||
|
||||
scanForDangerousFunctions(&M);
|
||||
|
||||
for (Function &F : M) {
|
||||
|
||||
if (debug) {
|
||||
|
@ -1,79 +0,0 @@
|
||||
# Using afl++ with partial instrumentation
|
||||
|
||||
This file describes how you can selectively instrument only the source files
|
||||
that are interesting to you using the LLVM instrumentation provided by
|
||||
afl++
|
||||
|
||||
Originally developed by Christian Holler (:decoder) <choller@mozilla.com>.
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
When building and testing complex programs where only a part of the program is
|
||||
the fuzzing target, it often helps to only instrument the necessary parts of
|
||||
the program, leaving the rest uninstrumented. This helps to focus the fuzzer
|
||||
on the important parts of the program, avoiding undesired noise and
|
||||
disturbance by uninteresting code being exercised.
|
||||
|
||||
For this purpose, I have added a "partial instrumentation" support to the LLVM
|
||||
mode of AFLFuzz that allows you to specify on a source file level which files
|
||||
should be compiled with or without instrumentation.
|
||||
|
||||
|
||||
## 2) Building the LLVM module
|
||||
|
||||
The new code is part of the existing afl++ LLVM module in the llvm_mode/
|
||||
subdirectory. There is nothing specifically to do :)
|
||||
|
||||
|
||||
## 3) How to use the partial instrumentation mode
|
||||
|
||||
In order to build with partial instrumentation, you need to build with
|
||||
afl-clang-fast and afl-clang-fast++ respectively. The only required change is
|
||||
that you need to set the environment variable AFL_LLVM_INSTRUMENT_FILE when calling
|
||||
the compiler.
|
||||
|
||||
The environment variable must point to a file containing all the filenames
|
||||
that should be instrumented. For matching, the filename that is being compiled
|
||||
must end in the filename entry contained in this the instrument file list (to avoid breaking
|
||||
the matching when absolute paths are used during compilation).
|
||||
|
||||
For example if your source tree looks like this:
|
||||
|
||||
```
|
||||
project/
|
||||
project/feature_a/a1.cpp
|
||||
project/feature_a/a2.cpp
|
||||
project/feature_b/b1.cpp
|
||||
project/feature_b/b2.cpp
|
||||
```
|
||||
|
||||
and you only want to test feature_a, then create a the instrument file list file containing:
|
||||
|
||||
```
|
||||
feature_a/a1.cpp
|
||||
feature_a/a2.cpp
|
||||
```
|
||||
|
||||
However if the instrument file list file contains only this, it works as well:
|
||||
|
||||
```
|
||||
a1.cpp
|
||||
a2.cpp
|
||||
```
|
||||
|
||||
but it might lead to files being unwantedly instrumented if the same filename
|
||||
exists somewhere else in the project directories.
|
||||
|
||||
The created the instrument file list file is then set to AFL_LLVM_INSTRUMENT_FILE when you compile
|
||||
your program. For each file that didn't match the the instrument file list, the compiler will
|
||||
issue a warning at the end stating that no blocks were instrumented. If you
|
||||
didn't intend to instrument that file, then you can safely ignore that warning.
|
||||
|
||||
For old LLVM versions this feature might require to be compiled with debug
|
||||
information (-g), however at least from llvm version 6.0 onwards this is not
|
||||
required anymore (and might hurt performance and crash detection, so better not
|
||||
use -g).
|
||||
|
||||
## 4) UNIX-style filename pattern matching
|
||||
You can add UNIX-style pattern matching in the the instrument file list entries. See `man
|
||||
fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
|
86
llvm_mode/README.instrument_list.md
Normal file
86
llvm_mode/README.instrument_list.md
Normal file
@ -0,0 +1,86 @@
|
||||
# Using afl++ with partial instrumentation
|
||||
|
||||
This file describes how you can selectively instrument only the source files
|
||||
or functions that are interesting to you using the LLVM instrumentation
|
||||
provided by afl++
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
When building and testing complex programs where only a part of the program is
|
||||
the fuzzing target, it often helps to only instrument the necessary parts of
|
||||
the program, leaving the rest uninstrumented. This helps to focus the fuzzer
|
||||
on the important parts of the program, avoiding undesired noise and
|
||||
disturbance by uninteresting code being exercised.
|
||||
|
||||
For this purpose, a "partial instrumentation" support en par with llvm sancov
|
||||
is provided by afl++ that allows you to specify on a source file and function
|
||||
level which function should be compiled with or without instrumentation.
|
||||
|
||||
Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead:
|
||||
https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
|
||||
|
||||
The llvm sancov list format is fully supported by afl++, however afl++ has
|
||||
more flexibility.
|
||||
|
||||
## 2) Building the LLVM module
|
||||
|
||||
The new code is part of the existing afl++ LLVM module in the llvm_mode/
|
||||
subdirectory. There is nothing specifically to do :)
|
||||
|
||||
## 3) How to use the partial instrumentation mode
|
||||
|
||||
In order to build with partial instrumentation, you need to build with
|
||||
afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++.
|
||||
The only required change is that you need to set either the environment variable
|
||||
AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename.
|
||||
|
||||
That file then contains the filenames or functions that should be instrumented
|
||||
(AFL_LLVM_ALLOWLIST) or should specifically NOT be instrumented (AFL_LLVM_DENYLIST).
|
||||
|
||||
For matching, the function/filename that is being compiled must end in the
|
||||
function/filename entry contained in this instrument file list (to avoid
|
||||
breaking the matching when absolute paths are used during compilation).
|
||||
|
||||
**NOTE:** In builds with optimization enabled functions might be inlined and would not match!
|
||||
|
||||
For example if your source tree looks like this:
|
||||
```
|
||||
project/
|
||||
project/feature_a/a1.cpp
|
||||
project/feature_a/a2.cpp
|
||||
project/feature_b/b1.cpp
|
||||
project/feature_b/b2.cpp
|
||||
```
|
||||
|
||||
and you only want to test feature_a, then create a instrument file list file containing:
|
||||
```
|
||||
feature_a/a1.cpp
|
||||
feature_a/a2.cpp
|
||||
```
|
||||
|
||||
However if the instrument file list file contains only this, it works as well:
|
||||
```
|
||||
a1.cpp
|
||||
a2.cpp
|
||||
```
|
||||
but it might lead to files being unwantedly instrumented if the same filename
|
||||
exists somewhere else in the project directories.
|
||||
|
||||
You can also specify function names. Note that for C++ the function names
|
||||
must be mangled to match!
|
||||
|
||||
afl++ is able to identify if an entry is a filename or a function.
|
||||
However if you want to be sure (and compliant to the sancov allow/blocklist
|
||||
format), you can specify source file entries like this:
|
||||
```
|
||||
src: *malloc.c
|
||||
```
|
||||
and function entries like this:
|
||||
```
|
||||
fun: MallocFoo
|
||||
```
|
||||
Note that whitespace is ignored and comments (`# foo`) are supported.
|
||||
|
||||
## 4) UNIX-style pattern matching
|
||||
You can add UNIX-style pattern matching in the the instrument file list entries.
|
||||
See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
|
@ -35,8 +35,8 @@ bit_width may be 64, 32 or 16.
|
||||
A new experimental feature is splitting floating point comparisons into a
|
||||
series of sign, exponent and mantissa comparisons followed by splitting each
|
||||
of them into 8 bit comparisons when necessary.
|
||||
It is activated with the `AFL_LLVM_LAF_SPLIT_FLOATS` setting, available only
|
||||
when `AFL_LLVM_LAF_SPLIT_COMPARES` is set.
|
||||
It is activated with the `AFL_LLVM_LAF_SPLIT_FLOATS` setting.
|
||||
Note that setting this automatically activates `AFL_LLVM_LAF_SPLIT_COMPARES`
|
||||
|
||||
You can also set `AFL_LLVM_LAF_ALL` and have all of the above enabled :-)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
## TLDR;
|
||||
|
||||
This version requires a current llvm 11 compiled from the github master.
|
||||
This version requires a current llvm 11+ compiled from the github master.
|
||||
|
||||
1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
|
||||
coverage than anything else that is out there in the AFL world
|
||||
@ -10,16 +10,13 @@ This version requires a current llvm 11 compiled from the github master.
|
||||
2. You can use it together with llvm_mode: laf-intel and the instrument file listing
|
||||
features and can be combined with cmplog/Redqueen
|
||||
|
||||
3. It only works with llvm 11 (current github master state)
|
||||
3. It only works with llvm 11+
|
||||
|
||||
4. AUTODICTIONARY feature! see below
|
||||
|
||||
5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`.
|
||||
Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
|
||||
|
||||
6. If a target uses _init functions or early constructors then additionally
|
||||
set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise!
|
||||
|
||||
## Introduction and problem description
|
||||
|
||||
A big issue with how afl/afl++ works is that the basic block IDs that are
|
||||
@ -61,9 +58,9 @@ AUTODICTIONARY: 11 strings found
|
||||
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
|
||||
```
|
||||
|
||||
## Getting llvm 11
|
||||
## Getting llvm 11+
|
||||
|
||||
### Installing llvm 11 from the llvm repository
|
||||
### Installing llvm from the llvm repository (version 11)
|
||||
|
||||
Installing the llvm snapshot builds is easy and mostly painless:
|
||||
|
||||
@ -83,7 +80,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
|
||||
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
|
||||
```
|
||||
|
||||
### Building llvm 11 yourself
|
||||
### Building llvm yourself (version 12)
|
||||
|
||||
Building llvm from github takes quite some long time and is not painless:
|
||||
```
|
||||
@ -108,15 +105,12 @@ make install
|
||||
|
||||
Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc.
|
||||
|
||||
Also the instrument file listing (AFL_LLVM_INSTRUMENT_FILE -> [README.instrument_file.md](README.instrument_file.md)) and
|
||||
Also the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -> [README.instrument_list.md](README.instrument_list.md)) and
|
||||
laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
|
||||
InsTrim (control flow graph instrumentation) is supported and recommended!
|
||||
(set `AFL_LLVM_INSTRUMENT=CFG`)
|
||||
|
||||
Example:
|
||||
```
|
||||
CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
|
||||
export AFL_LLVM_INSTRUMENT=CFG
|
||||
make
|
||||
```
|
||||
|
||||
@ -125,21 +119,26 @@ NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
|
||||
|
||||
## AUTODICTIONARY feature
|
||||
|
||||
Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
|
||||
target binary based on string compare and memory compare functions.
|
||||
afl-fuzz will automatically get these transmitted when starting to fuzz.
|
||||
This improves coverage on a lot of targets.
|
||||
While compiling, automatically a dictionary based on string comparisons is
|
||||
generated put into the target binary. This dictionary is transfered to afl-fuzz
|
||||
on start. This improves coverage statistically by 5-10% :)
|
||||
|
||||
## Fixed memory map
|
||||
|
||||
To speed up fuzzing, the shared memory map is hard set to a specific address,
|
||||
by default 0x10000. In most cases this will work without any problems.
|
||||
To speed up fuzzing, it is possible to set a fixed shared memory map.
|
||||
Recommened is the value 0x10000.
|
||||
In most cases this will work without any problems. However if a target uses
|
||||
early constructors, ifuncs or a deferred forkserver this can crash the target.
|
||||
On unusual operating systems/processors/kernels or weird libraries this might
|
||||
fail so to change the fixed address at compile time set
|
||||
AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address
|
||||
to be dynamic - the original afl way, which is slower).
|
||||
AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which
|
||||
is safer but also slower).
|
||||
|
||||
## Document edge IDs
|
||||
|
||||
Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge
|
||||
ID was given to which function. This helps to identify functions with variable
|
||||
bytes or which functions were touched by an input.
|
||||
|
||||
## Solving difficult targets
|
||||
|
||||
@ -147,6 +146,8 @@ Some targets are difficult because the configure script does unusual stuff that
|
||||
is unexpected for afl. See the next chapter `Potential issues` how to solve
|
||||
these.
|
||||
|
||||
### Example: ffmpeg
|
||||
|
||||
An example of a hard to solve target is ffmpeg. Here is how to successfully
|
||||
instrument it:
|
||||
|
||||
@ -156,7 +157,7 @@ instrument it:
|
||||
when compiling, so we have to trick configure:
|
||||
|
||||
```
|
||||
./configure --enable-lto --disable-shared
|
||||
./configure --enable-lto --disable-shared --disable-inline-asm
|
||||
```
|
||||
|
||||
3. Now the configuration is done - and we edit the settings in `./ffbuild/config.mak`
|
||||
@ -186,6 +187,31 @@ instrument it:
|
||||
|
||||
4. Then type make, wait for a long time and you are done :)
|
||||
|
||||
### Example: WebKit jsc
|
||||
|
||||
Building jsc is difficult as the build script has bugs.
|
||||
|
||||
1. checkout Webkit:
|
||||
```
|
||||
svn checkout https://svn.webkit.org/repository/webkit/trunk WebKit
|
||||
cd WebKit
|
||||
```
|
||||
|
||||
2. Fix the build environment:
|
||||
```
|
||||
mkdir -p WebKitBuild/Release
|
||||
cd WebKitBuild/Release
|
||||
ln -s ../../../../../usr/bin/llvm-ar-12 llvm-ar-12
|
||||
ln -s ../../../../../usr/bin/llvm-ranlib-12 llvm-ranlib-12
|
||||
cd ../..
|
||||
```
|
||||
|
||||
3. Build :)
|
||||
|
||||
```
|
||||
Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-12' -DCMAKE_RANLIB='llvm-ranlib-12' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON"
|
||||
```
|
||||
|
||||
## Potential issues
|
||||
|
||||
### compiling libraries fails
|
||||
@ -220,28 +246,19 @@ AS=llvm-as ...
|
||||
afl-clang-lto is still work in progress.
|
||||
|
||||
Known issues:
|
||||
* Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously
|
||||
* Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously
|
||||
* Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
|
||||
|
||||
Hence if building a target with afl-clang-lto fails try to build it with llvm11
|
||||
and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
|
||||
Hence if building a target with afl-clang-lto fails try to build it with llvm12
|
||||
and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and
|
||||
`CXXFLAGS=-flto=full`).
|
||||
|
||||
If this succeeeds then there is an issue with afl-clang-lto. Please report at
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
|
||||
|
||||
Even some targets where clang-11 fails can be build if the fail is just in
|
||||
Even some targets where clang-12 fails can be build if the fail is just in
|
||||
`./configure`, see `Solving difficult targets` above.
|
||||
|
||||
### Target crashes immediately
|
||||
|
||||
If the target is using early constructors (priority values smaller than 6)
|
||||
or have their own _init/.init functions and these are instrumented then the
|
||||
target will likely crash when started. This can be avoided by compiling with
|
||||
`AFL_LLVM_MAP_DYNAMIC=1` .
|
||||
|
||||
This can e.g. happen with OpenSSL.
|
||||
|
||||
## History
|
||||
|
||||
This was originally envisioned by hexcoder- in Summer 2019, however we saw no
|
||||
@ -270,7 +287,7 @@ Still more problems came up though as this only works without bugs from
|
||||
llvm 9 onwards, and with high optimization the link optimization ruins
|
||||
the instrumented control flow graph.
|
||||
|
||||
This is all now fixed with llvm 11. The llvm's own linker is now able to
|
||||
This is all now fixed with llvm 11+. The llvm's own linker is now able to
|
||||
load passes and this bypasses all problems we had.
|
||||
|
||||
Happy end :)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
! llvm_mode works with llvm versions 3.4 up to 11 !
|
||||
! llvm_mode works with llvm versions 3.4 up to 12 !
|
||||
|
||||
The code in this directory allows you to instrument programs for AFL using
|
||||
true compiler-level instrumentation, instead of the more crude
|
||||
@ -109,7 +109,7 @@ Several options are present to make llvm_mode faster or help it rearrange
|
||||
the code to make afl-fuzz path discovery easier.
|
||||
|
||||
If you need just to instrument specific parts of the code, you can the instrument file list
|
||||
which C/C++ files to actually instrument. See [README.instrument_file](README.instrument_file.md)
|
||||
which C/C++ files to actually instrument. See [README.instrument_list](README.instrument_list.md)
|
||||
|
||||
For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md)
|
||||
|
||||
@ -183,4 +183,4 @@ AFL_LLVM_INSTRUMENT=PCGUARD make
|
||||
```
|
||||
|
||||
Note that this us currently the default, as it is the best mode.
|
||||
If you have llvm 11 and compiled afl-clang-lto - this is the only better mode.
|
||||
If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode.
|
||||
|
@ -52,6 +52,21 @@ afl-clang-fast -o fuzz_target fuzz_target.c -lwhat_you_need_for_your_target
|
||||
And that is it!
|
||||
The speed increase is usually x10 to x20.
|
||||
|
||||
If you want to be able to compile the target without afl-clang-fast/lto then
|
||||
add this just after the includes:
|
||||
|
||||
```
|
||||
#ifndef __AFL_FUZZ_TESTCASE_LEN
|
||||
ssize_t fuzz_len;
|
||||
#define __AFL_FUZZ_TESTCASE_LEN fuzz_len
|
||||
unsigned char fuzz_buf[1024000];
|
||||
#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
|
||||
#define __AFL_FUZZ_INIT() void sync(void);
|
||||
#define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ?
|
||||
#define __AFL_INIT() sync()
|
||||
#endif
|
||||
```
|
||||
|
||||
## 3) deferred initialization
|
||||
|
||||
AFL tries to optimize performance by executing the targeted binary just once,
|
||||
@ -100,6 +115,33 @@ will keep working normally when compiled with a tool other than afl-clang-fast.
|
||||
Finally, recompile the program with afl-clang-fast (afl-gcc or afl-clang will
|
||||
*not* generate a deferred-initialization binary) - and you should be all set!
|
||||
|
||||
*NOTE:* In the code between `main` and `__AFL_INIT()` should not be any code
|
||||
run that is instrumented - otherwise a crash might occure.
|
||||
In case this is useful (e.g. for expensive one time initialization) you can
|
||||
try to do the following:
|
||||
|
||||
Add after the includes:
|
||||
```
|
||||
extern unsigned char *__afl_area_ptr;
|
||||
#define MAX_DUMMY_SIZE 256000
|
||||
|
||||
__attribute__((constructor(1))) void __afl_protect(void) {
|
||||
#ifdef MAP_FIXED_NOREPLACE
|
||||
__afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if ((uint64_t)__afl_area_ptr == -1)
|
||||
#endif
|
||||
__afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if ((uint64_t)__afl_area_ptr == -1)
|
||||
__afl_area_ptr = (unsigned char*) mmap(NULL, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
```
|
||||
and just before `__AFL_INIT()`:
|
||||
```
|
||||
munmap(__afl_area_ptr, MAX_DUMMY_SIZE);
|
||||
__afl_area_ptr = NULL;
|
||||
```
|
||||
|
||||
## 4) persistent mode
|
||||
|
||||
Some libraries provide APIs that are stateless, or whose state can be reset in
|
||||
|
@ -161,7 +161,9 @@ static void find_obj(u8 *argv0) {
|
||||
|
||||
static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
|
||||
preprocessor_only = 0;
|
||||
u8 have_pic = 0;
|
||||
u8 *name;
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
|
||||
@ -228,7 +230,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
if (lto_mode) {
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST")) {
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
@ -243,38 +246,60 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
// laf
|
||||
if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-switches-pass.so", obj_path);
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path);
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-switches-pass.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("LAF_TRANSFORM_COMPARES") ||
|
||||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
|
||||
|
||||
if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && lto_mode)
|
||||
WARNF(
|
||||
"using AFL_LLVM_LAF_TRANSFORM_COMPARES together with "
|
||||
"AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only "
|
||||
"AFL_LLVM_LTO_AUTODICTIONARY.");
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/compare-transform-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] = alloc_printf(
|
||||
"-Wl,-mllvm=-load=%s/compare-transform-pass.so", obj_path);
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/compare-transform-pass.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) {
|
||||
if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
|
||||
getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-compares-pass.so", obj_path);
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/split-compares-pass.so", obj_path);
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-compares-pass.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -284,24 +309,37 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
unsetenv("AFL_LD_CALLER");
|
||||
if (cmplog_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/cmplog-routines-pass.so", obj_path);
|
||||
if (lto_mode) {
|
||||
|
||||
// reuse split switches from laf
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-switches-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] = alloc_printf(
|
||||
"-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path);
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/cmplog-routines-pass.so", obj_path);
|
||||
|
||||
// reuse split switches from laf
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/split-switches-pass.so", obj_path);
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fno-inline";
|
||||
|
||||
@ -309,22 +347,46 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
|
||||
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
|
||||
if (instrument_mode == INSTRUMENT_CFG)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path);
|
||||
if (cmplog_mode)
|
||||
unsetenv("AFL_LLVM_LTO_AUTODICTIONARY");
|
||||
else
|
||||
cc_params[cc_par_cnt++] = alloc_printf(
|
||||
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
|
||||
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";
|
||||
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_ptr);
|
||||
cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", AFL_REAL_LD);
|
||||
#else
|
||||
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
|
||||
#endif
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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 {
|
||||
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 4 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && \
|
||||
(LLVM_VERSION_MINOR > 0 || LLVM_VERSION_PATCH >= 1))
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
|
||||
#else
|
||||
FATAL("pcguard instrumentation requires llvm 4.0.1+");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
@ -359,6 +421,19 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
u32 idx;
|
||||
if (lto_mode && argc > 1) {
|
||||
|
||||
for (idx = 1; idx < argc; idx++) {
|
||||
|
||||
if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
|
||||
|
||||
}
|
||||
|
||||
if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC";
|
||||
|
||||
}
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
|
||||
while (--argc) {
|
||||
@ -379,6 +454,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
|
||||
continue;
|
||||
|
||||
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
|
||||
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
|
||||
|
||||
if (!strcmp(cur, "-E")) preprocessor_only = 1;
|
||||
if (!strcmp(cur, "-shared")) shared_linking = 1;
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
@ -452,9 +533,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
|
||||
getenv("LAF_TRANSFORM_COMPARES") ||
|
||||
(lto_mode && (getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
|
||||
getenv("AFL_LLVM_AUTODICTIONARY")))) {
|
||||
getenv("LAF_TRANSFORM_COMPARES") || lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
|
||||
@ -500,13 +579,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
"int __afl_sharedmem_fuzzing = 1;"
|
||||
"extern unsigned int *__afl_fuzz_len;"
|
||||
"extern unsigned char *__afl_fuzz_ptr;"
|
||||
"unsigned char *__afl_fuzz_alt_ptr;";
|
||||
"unsigned char __afl_fuzz_alt[1024000];"
|
||||
"unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
|
||||
"(__afl_fuzz_alt_ptr = (unsigned char *) malloc(1 * 1024 * 1024)))";
|
||||
"__afl_fuzz_alt_ptr)";
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : read(0, "
|
||||
"__afl_fuzz_alt_ptr, 1 * 1024 * 1024))";
|
||||
"-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
|
||||
"(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1024000)) == 0xffffffff "
|
||||
"? 0 : *__afl_fuzz_len)";
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-D__AFL_LOOP(_A)="
|
||||
@ -543,6 +624,18 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (preprocessor_only) {
|
||||
|
||||
/* In the preprocessor_only case (-E), we are not actually compiling at
|
||||
all but requesting the compiler to output preprocessed sources only.
|
||||
We must not add the runtime in this case because the compiler will
|
||||
simply output its binary content back on stdout, breaking any build
|
||||
systems that rely on a separate source preprocessing step. */
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
switch (bit_mode) {
|
||||
|
||||
@ -585,6 +678,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (!shared_linking)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
|
||||
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
@ -617,6 +714,14 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) &&
|
||||
getenv("AFL_DONT_OPTIMIZE"))
|
||||
WARNF(
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
|
||||
"for file matching, only function matching!");
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
|
||||
getenv("INSTRIM_LIB")) {
|
||||
|
||||
@ -660,7 +765,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
|
||||
strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) {
|
||||
strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) {
|
||||
|
||||
if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
@ -763,9 +868,21 @@ int main(int argc, char **argv, char **envp) {
|
||||
#if LLVM_VERSION_MAJOR <= 6
|
||||
instrument_mode = INSTRUMENT_AFL;
|
||||
#else
|
||||
if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST"))
|
||||
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
|
||||
|
||||
instrument_mode = INSTRUMENT_AFL;
|
||||
else
|
||||
WARNF(
|
||||
"switching to classic instrumentation because "
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use "
|
||||
"-fsanitize-coverage-allowlist=allowlist.txt or "
|
||||
"-fsanitize-coverage-blocklist=denylist.txt if you want to use "
|
||||
"PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ "
|
||||
"SanitizerCoverage.html#partially-disabling-instrumentation");
|
||||
|
||||
} else
|
||||
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
#endif
|
||||
|
||||
@ -812,10 +929,17 @@ int main(int argc, char **argv, char **envp) {
|
||||
"together");
|
||||
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD &&
|
||||
(getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")))
|
||||
WARNF(
|
||||
(getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
|
||||
getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
|
||||
getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")))
|
||||
FATAL(
|
||||
"Instrumentation type PCGUARD does not support "
|
||||
"AFL_LLVM_INSTRUMENT_FILE!");
|
||||
"AFL_LLVM_ALLOWLIST/DENYLIST! Use "
|
||||
"-fsanitize-coverage-allowlist=allowlist.txt or "
|
||||
"-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm "
|
||||
"12+), see "
|
||||
"https://clang.llvm.org/docs/"
|
||||
"SanitizerCoverage.html#partially-disabling-instrumentation");
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
|
||||
|
||||
@ -871,6 +995,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_PATH: path to instrumenting pass and runtime "
|
||||
"(afl-llvm-rt.*o)\n"
|
||||
"AFL_LLVM_DOCUMENT_IDS: document edge IDs given to which function (LTO "
|
||||
"only)\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_CFISAN: activate control flow sanitizer\n"
|
||||
@ -895,6 +1021,10 @@ int main(int argc, char **argv, char **envp) {
|
||||
#ifdef AFL_CLANG_FLTO
|
||||
SAYF(
|
||||
"\nafl-clang-lto specific environment variables:\n"
|
||||
"AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), e.g. "
|
||||
"0x10000\n"
|
||||
"AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
|
||||
"functions they are in into this file\n"
|
||||
"AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
|
||||
"global var\n"
|
||||
"AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
|
||||
@ -939,7 +1069,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
u32 map_size = atoi(ptr2);
|
||||
if (map_size != MAP_SIZE)
|
||||
FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast");
|
||||
WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast");
|
||||
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (debug) {
|
||||
|
||||
(void)getcwd(thecwd, sizeof(thecwd));
|
||||
if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, ".");
|
||||
|
||||
SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd);
|
||||
for (i = 0; i < argc; i++)
|
||||
|
@ -14,11 +14,16 @@
|
||||
#include <fstream>
|
||||
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#define IS_EXTERN extern
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static std::list<std::string> myInstrumentList;
|
||||
static std::list<std::string> allowListFiles;
|
||||
static std::list<std::string> allowListFunctions;
|
||||
static std::list<std::string> denyListFiles;
|
||||
static std::list<std::string> denyListFunctions;
|
||||
|
||||
char *getBBName(const llvm::BasicBlock *BB) {
|
||||
|
||||
@ -55,15 +60,18 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
"asan.",
|
||||
"llvm.",
|
||||
"sancov.",
|
||||
"__ubsan_handle_",
|
||||
"__ubsan_",
|
||||
"ign.",
|
||||
"__afl_",
|
||||
"_fini",
|
||||
"__libc_csu",
|
||||
"__asan",
|
||||
"__msan",
|
||||
"__cmplog",
|
||||
"__sancov",
|
||||
"msan.",
|
||||
"LLVMFuzzer",
|
||||
"__decide_deferred",
|
||||
"maybe_duplicate_stderr",
|
||||
"discard_output",
|
||||
"close_stdout",
|
||||
@ -85,36 +93,246 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
|
||||
void initInstrumentList() {
|
||||
|
||||
char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE");
|
||||
if (!instrumentListFilename)
|
||||
instrumentListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||
if (instrumentListFilename) {
|
||||
char *allowlist = getenv("AFL_LLVM_ALLOWLIST");
|
||||
if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE");
|
||||
if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST");
|
||||
char *denylist = getenv("AFL_LLVM_DENYLIST");
|
||||
if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST");
|
||||
|
||||
if (allowlist && denylist)
|
||||
FATAL(
|
||||
"You can only specify either AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST "
|
||||
"but not both!");
|
||||
|
||||
if (allowlist) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instrumentListFilename);
|
||||
if (!fileStream)
|
||||
report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE");
|
||||
fileStream.open(allowlist);
|
||||
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_ALLOWLIST");
|
||||
getline(fileStream, line);
|
||||
|
||||
while (fileStream) {
|
||||
|
||||
myInstrumentList.push_back(line);
|
||||
getline(fileStream, line);
|
||||
int is_file = -1;
|
||||
std::size_t npos;
|
||||
std::string original_line = line;
|
||||
|
||||
line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
|
||||
line.end());
|
||||
|
||||
// remove # and following
|
||||
if ((npos = line.find("#")) != std::string::npos)
|
||||
line = line.substr(0, npos);
|
||||
|
||||
if (line.compare(0, 4, "fun:") == 0) {
|
||||
|
||||
is_file = 0;
|
||||
line = line.substr(4);
|
||||
|
||||
} else if (line.compare(0, 9, "function:") == 0) {
|
||||
|
||||
is_file = 0;
|
||||
line = line.substr(9);
|
||||
|
||||
} else if (line.compare(0, 4, "src:") == 0) {
|
||||
|
||||
is_file = 1;
|
||||
line = line.substr(4);
|
||||
|
||||
} else if (line.compare(0, 7, "source:") == 0) {
|
||||
|
||||
is_file = 1;
|
||||
line = line.substr(7);
|
||||
|
||||
}
|
||||
|
||||
if (line.find(":") != std::string::npos) {
|
||||
|
||||
FATAL("invalid line in AFL_LLVM_ALLOWLIST: %s", original_line.c_str());
|
||||
|
||||
}
|
||||
|
||||
if (line.length() > 0) {
|
||||
|
||||
// if the entry contains / or . it must be a file
|
||||
if (is_file == -1)
|
||||
if (line.find("/") != std::string::npos ||
|
||||
line.find(".") != std::string::npos)
|
||||
is_file = 1;
|
||||
// otherwise it is a function
|
||||
|
||||
if (is_file == 1)
|
||||
allowListFiles.push_back(line);
|
||||
else
|
||||
allowListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded allowlist with %zu file and %zu function entries\n",
|
||||
allowListFiles.size(), allowListFunctions.size());
|
||||
|
||||
}
|
||||
|
||||
if (denylist) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(denylist);
|
||||
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_DENYLIST");
|
||||
getline(fileStream, line);
|
||||
|
||||
while (fileStream) {
|
||||
|
||||
int is_file = -1;
|
||||
std::size_t npos;
|
||||
std::string original_line = line;
|
||||
|
||||
line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
|
||||
line.end());
|
||||
|
||||
// remove # and following
|
||||
if ((npos = line.find("#")) != std::string::npos)
|
||||
line = line.substr(0, npos);
|
||||
|
||||
if (line.compare(0, 4, "fun:") == 0) {
|
||||
|
||||
is_file = 0;
|
||||
line = line.substr(4);
|
||||
|
||||
} else if (line.compare(0, 9, "function:") == 0) {
|
||||
|
||||
is_file = 0;
|
||||
line = line.substr(9);
|
||||
|
||||
} else if (line.compare(0, 4, "src:") == 0) {
|
||||
|
||||
is_file = 1;
|
||||
line = line.substr(4);
|
||||
|
||||
} else if (line.compare(0, 7, "source:") == 0) {
|
||||
|
||||
is_file = 1;
|
||||
line = line.substr(7);
|
||||
|
||||
}
|
||||
|
||||
if (line.find(":") != std::string::npos) {
|
||||
|
||||
FATAL("invalid line in AFL_LLVM_DENYLIST: %s", original_line.c_str());
|
||||
|
||||
}
|
||||
|
||||
if (line.length() > 0) {
|
||||
|
||||
// if the entry contains / or . it must be a file
|
||||
if (is_file == -1)
|
||||
if (line.find("/") != std::string::npos ||
|
||||
line.find(".") != std::string::npos)
|
||||
is_file = 1;
|
||||
// otherwise it is a function
|
||||
|
||||
if (is_file == 1)
|
||||
denyListFiles.push_back(line);
|
||||
else
|
||||
denyListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded denylist with %zu file and %zu function entries\n",
|
||||
denyListFiles.size(), denyListFunctions.size());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool isInInstrumentList(llvm::Function *F) {
|
||||
void scanForDangerousFunctions(llvm::Module *M) {
|
||||
|
||||
// is this a function with code? If it is external we dont instrument it
|
||||
// anyway and cant be in the the instrument file list. Or if it is ignored.
|
||||
if (!F->size() || isIgnoreFunction(F)) return false;
|
||||
if (!M) return;
|
||||
|
||||
// if we do not have a the instrument file list return true
|
||||
if (myInstrumentList.empty()) return true;
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
|
||||
|
||||
for (GlobalIFunc &IF : M->ifuncs()) {
|
||||
|
||||
StringRef ifunc_name = IF.getName();
|
||||
Constant *r = IF.getResolver();
|
||||
StringRef r_name = cast<Function>(r->getOperand(0))->getName();
|
||||
if (!be_quiet)
|
||||
fprintf(stderr,
|
||||
"Info: Found an ifunc with name %s that points to resolver "
|
||||
"function %s, we will not instrument this, putting it into the "
|
||||
"block list.\n",
|
||||
ifunc_name.str().c_str(), r_name.str().c_str());
|
||||
denyListFunctions.push_back(r_name.str());
|
||||
|
||||
}
|
||||
|
||||
GlobalVariable *GV = M->getNamedGlobal("llvm.global_ctors");
|
||||
if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
|
||||
|
||||
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||
|
||||
if (InitList) {
|
||||
|
||||
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
||||
|
||||
if (ConstantStruct *CS =
|
||||
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
|
||||
|
||||
if (CS->getNumOperands() >= 2) {
|
||||
|
||||
if (CS->getOperand(1)->isNullValue())
|
||||
break; // Found a null terminator, stop here.
|
||||
|
||||
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
|
||||
int Priority = CI ? CI->getSExtValue() : 0;
|
||||
|
||||
Constant *FP = CS->getOperand(1);
|
||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
||||
if (CE->isCast()) FP = CE->getOperand(0);
|
||||
if (Function *F = dyn_cast<Function>(FP)) {
|
||||
|
||||
if (!F->isDeclaration() &&
|
||||
strncmp(F->getName().str().c_str(), "__afl", 5) != 0) {
|
||||
|
||||
if (!be_quiet)
|
||||
fprintf(stderr,
|
||||
"Info: Found constructor function %s with prio "
|
||||
"%u, we will not instrument this, putting it into a "
|
||||
"block list.\n",
|
||||
F->getName().str().c_str(), Priority);
|
||||
denyListFunctions.push_back(F->getName().str());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static std::string getSourceName(llvm::Function *F) {
|
||||
|
||||
// let's try to get the filename for the function
|
||||
auto bb = &F->getEntryBlock();
|
||||
@ -128,51 +346,18 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
|
||||
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||
|
||||
unsigned int instLine = cDILoc->getLine();
|
||||
StringRef instFilename = cDILoc->getFilename();
|
||||
StringRef instFilename = cDILoc->getFilename();
|
||||
|
||||
if (instFilename.str().empty()) {
|
||||
|
||||
/* If the original location is empty, try using the inlined location
|
||||
*/
|
||||
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||
if (oDILoc) {
|
||||
|
||||
instFilename = oDILoc->getFilename();
|
||||
instLine = oDILoc->getLine();
|
||||
|
||||
}
|
||||
if (oDILoc) { instFilename = oDILoc->getFilename(); }
|
||||
|
||||
}
|
||||
|
||||
(void)instLine;
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myInstrumentList.begin();
|
||||
it != myInstrumentList.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
* check that the actual filename ends in the filename
|
||||
* specified in the list. We also allow UNIX-style pattern
|
||||
* matching */
|
||||
|
||||
if (instFilename.str().length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
|
||||
0) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return instFilename.str();
|
||||
|
||||
}
|
||||
|
||||
@ -181,15 +366,36 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
|
||||
DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
|
||||
|
||||
unsigned int instLine = cDILoc.getLineNumber();
|
||||
StringRef instFilename = cDILoc.getFilename();
|
||||
StringRef instFilename = cDILoc.getFilename();
|
||||
|
||||
(void)instLine;
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
return instFilename.str();
|
||||
|
||||
for (std::list<std::string>::iterator it = myInstrumentList.begin();
|
||||
it != myInstrumentList.end(); ++it) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return std::string("");
|
||||
|
||||
}
|
||||
|
||||
bool isInInstrumentList(llvm::Function *F) {
|
||||
|
||||
bool return_default = true;
|
||||
|
||||
// is this a function with code? If it is external we don't instrument it
|
||||
// anyway and it can't be in the instrument file list. Or if it is it is
|
||||
// ignored.
|
||||
if (!F->size() || isIgnoreFunction(F)) return false;
|
||||
|
||||
if (!denyListFiles.empty() || !denyListFunctions.empty()) {
|
||||
|
||||
if (!denyListFunctions.empty()) {
|
||||
|
||||
std::string instFunction = F->getName().str();
|
||||
|
||||
for (std::list<std::string>::iterator it = denyListFunctions.begin();
|
||||
it != denyListFunctions.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
@ -197,11 +403,95 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
* specified in the list. We also allow UNIX-style pattern
|
||||
* matching */
|
||||
|
||||
if (instFilename.str().length() >= it->length()) {
|
||||
if (instFunction.length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
|
||||
0) {
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the deny function list, "
|
||||
"not instrumenting ... \n",
|
||||
instFunction.c_str());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!denyListFiles.empty()) {
|
||||
|
||||
std::string source_file = getSourceName(F);
|
||||
|
||||
if (!source_file.empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = denyListFiles.begin();
|
||||
it != denyListFiles.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
* check that the actual filename ends in the filename
|
||||
* specified in the list. We also allow UNIX-style pattern
|
||||
* matching */
|
||||
|
||||
if (source_file.length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// we could not find out the location. in this case we say it is not
|
||||
// in the instrument file list
|
||||
if (!be_quiet)
|
||||
WARNF(
|
||||
"No debug information found for function %s, will be "
|
||||
"instrumented (recompile with -g -O[1-3]).",
|
||||
F->getName().str().c_str());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we do not have a instrument file list return true
|
||||
if (!allowListFiles.empty() || !allowListFunctions.empty()) {
|
||||
|
||||
return_default = false;
|
||||
|
||||
if (!allowListFunctions.empty()) {
|
||||
|
||||
std::string instFunction = F->getName().str();
|
||||
|
||||
for (std::list<std::string>::iterator it = allowListFunctions.begin();
|
||||
it != allowListFunctions.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
* check that the actual filename ends in the filename
|
||||
* specified in the list. We also allow UNIX-style pattern
|
||||
* matching */
|
||||
|
||||
if (instFunction.length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allow function list, "
|
||||
"instrumenting ... \n",
|
||||
instFunction.c_str());
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -212,20 +502,56 @@ bool isInInstrumentList(llvm::Function *F) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (!allowListFiles.empty()) {
|
||||
|
||||
#endif
|
||||
else {
|
||||
std::string source_file = getSourceName(F);
|
||||
|
||||
// we could not find out the location. in this case we say it is not
|
||||
// in the the instrument file list
|
||||
if (!source_file.empty()) {
|
||||
|
||||
return false;
|
||||
for (std::list<std::string>::iterator it = allowListFiles.begin();
|
||||
it != allowListFiles.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
* check that the actual filename ends in the filename
|
||||
* specified in the list. We also allow UNIX-style pattern
|
||||
* matching */
|
||||
|
||||
if (source_file.length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"Function %s is in the allowlist (%s), "
|
||||
"instrumenting ... \n",
|
||||
F->getName().str().c_str(), source_file.c_str());
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// we could not find out the location. In this case we say it is not
|
||||
// in the instrument file list
|
||||
if (!be_quiet)
|
||||
WARNF(
|
||||
"No debug information found for function %s, will not be "
|
||||
"instrumented (recompile with -g -O[1-3]).",
|
||||
F->getName().str().c_str());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
return false;
|
||||
return return_default;
|
||||
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,16 @@ bool isIgnoreFunction(const llvm::Function *F);
|
||||
void initInstrumentList();
|
||||
bool isInInstrumentList(llvm::Function *F);
|
||||
unsigned long long int calculateCollisions(uint32_t edges);
|
||||
void scanForDangerousFunctions(llvm::Module *M);
|
||||
|
||||
#ifndef IS_EXTERN
|
||||
#define IS_EXTERN
|
||||
#endif
|
||||
|
||||
IS_EXTERN int debug;
|
||||
IS_EXTERN int be_quiet;
|
||||
|
||||
#undef IS_EXTERN
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -73,8 +73,8 @@ struct InsTrimLTO : public ModulePass {
|
||||
protected:
|
||||
uint32_t function_minimum_size = 1;
|
||||
char * skip_nozero = NULL;
|
||||
int afl_global_id = 1, debug = 0, autodictionary = 0;
|
||||
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0;
|
||||
int afl_global_id = 1, autodictionary = 1;
|
||||
uint32_t inst_blocks = 0, inst_funcs = 0;
|
||||
uint64_t map_addr = 0x10000;
|
||||
|
||||
public:
|
||||
@ -127,10 +127,6 @@ struct InsTrimLTO : public ModulePass {
|
||||
|
||||
/* Process environment variables */
|
||||
|
||||
if (getenv("AFL_LLVM_AUTODICTIONARY") ||
|
||||
getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
|
||||
autodictionary = 1;
|
||||
|
||||
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
|
||||
|
||||
if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
|
||||
@ -705,7 +701,7 @@ struct InsTrimLTO : public ModulePass {
|
||||
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
if (skip_nozero) {
|
||||
if (skip_nozero == NULL) {
|
||||
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "llvm/Analysis/MemorySSAUpdater.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
@ -86,9 +87,9 @@ class AFLLTOPass : public ModulePass {
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
protected:
|
||||
int afl_global_id = 1, debug = 0, autodictionary = 0;
|
||||
int afl_global_id = 1, autodictionary = 0;
|
||||
uint32_t function_minimum_size = 1;
|
||||
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
||||
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
||||
uint64_t map_addr = 0x10000;
|
||||
char * skip_nozero = NULL;
|
||||
|
||||
@ -102,7 +103,14 @@ 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;
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
unsigned long long int moduleID =
|
||||
(((unsigned long long int)(rand() & 0xffffffff)) << 32) | getpid();
|
||||
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
@ -120,15 +128,21 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
if (getenv("AFL_LLVM_AUTODICTIONARY") ||
|
||||
getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
|
||||
autodictionary = 1;
|
||||
if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
|
||||
|
||||
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
|
||||
if ((documentFile = fopen(ptr, "a")) == NULL)
|
||||
WARNF("Cannot access document file %s", ptr);
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
|
||||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
|
||||
function_minimum_size = 2;
|
||||
}
|
||||
|
||||
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"))) {
|
||||
|
||||
@ -137,7 +151,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
map_addr = 0;
|
||||
|
||||
} else if (map_addr == 0) {
|
||||
} else if (getenv("AFL_LLVM_MAP_DYNAMIC")) {
|
||||
|
||||
FATAL(
|
||||
"AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
|
||||
@ -187,13 +201,39 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
|
||||
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
|
||||
|
||||
// This dumps all inialized global strings - might be useful in the future
|
||||
/*
|
||||
for (auto G=M.getGlobalList().begin(); G!=M.getGlobalList().end(); G++) {
|
||||
|
||||
GlobalVariable &GV=*G;
|
||||
if (!GV.getName().str().empty()) {
|
||||
|
||||
fprintf(stderr, "Global Variable: %s", GV.getName().str().c_str());
|
||||
if (GV.hasInitializer())
|
||||
if (auto *Val = dyn_cast<ConstantDataArray>(GV.getInitializer()))
|
||||
fprintf(stderr, " Value: \"%s\"", Val->getAsString().str().c_str());
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
scanForDangerousFunctions(&M);
|
||||
|
||||
/* Instrument all the things! */
|
||||
|
||||
int inst_blocks = 0;
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
// fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str());
|
||||
/*For debugging
|
||||
AttributeSet X = F.getAttributes().getFnAttributes();
|
||||
fprintf(stderr, "DEBUG: Module %s Function %s attributes %u\n",
|
||||
M.getName().str().c_str(), F.getName().str().c_str(),
|
||||
X.getNumAttributes());
|
||||
*/
|
||||
|
||||
if (F.size() < function_minimum_size) continue;
|
||||
if (isIgnoreFunction(&F)) continue;
|
||||
@ -204,7 +244,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr,
|
||||
"DEBUG: Function %s is not the instrument file listed\n",
|
||||
"DEBUG: Function %s is not in a source file that was specified "
|
||||
"in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
continue;
|
||||
|
||||
@ -250,14 +291,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;
|
||||
@ -270,6 +311,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;
|
||||
@ -487,18 +546,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];
|
||||
@ -536,6 +604,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
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++;
|
||||
@ -554,9 +624,34 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
do {
|
||||
|
||||
--i;
|
||||
BasicBlock * newBB = NULL;
|
||||
BasicBlock * origBB = &(*InsBlocks[i]);
|
||||
std::vector<BasicBlock *> Successors;
|
||||
Instruction * TI = origBB->getTerminator();
|
||||
uint32_t fs = origBB->getParent()->size();
|
||||
uint32_t countto;
|
||||
|
||||
if (BlockList.size()) {
|
||||
|
||||
int skip = 0;
|
||||
for (uint32_t k = 0; k < BlockList.size(); k++) {
|
||||
|
||||
if (origBB == BlockList[k]) {
|
||||
|
||||
if (debug)
|
||||
fprintf(
|
||||
stderr,
|
||||
"DEBUG: Function %s skipping BB with/after __afl_loop\n",
|
||||
F.getName().str().c_str());
|
||||
skip = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (skip) continue;
|
||||
|
||||
}
|
||||
|
||||
for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
|
||||
SI != SE; ++SI) {
|
||||
@ -566,15 +661,25 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (TI == NULL || TI->getNumSuccessors() < 2) continue;
|
||||
if (fs == 1) {
|
||||
|
||||
newBB = origBB;
|
||||
countto = 1;
|
||||
|
||||
} else {
|
||||
|
||||
if (TI == NULL || TI->getNumSuccessors() < 2) continue;
|
||||
countto = Successors.size();
|
||||
|
||||
}
|
||||
|
||||
// if (Successors.size() != TI->getNumSuccessors())
|
||||
// FATAL("Different successor numbers %lu <-> %u\n", Successors.size(),
|
||||
// TI->getNumSuccessors());
|
||||
|
||||
for (uint32_t j = 0; j < Successors.size(); j++) {
|
||||
for (uint32_t j = 0; j < countto; j++) {
|
||||
|
||||
BasicBlock *newBB = llvm::SplitEdge(origBB, Successors[j]);
|
||||
if (fs != 1) newBB = llvm::SplitEdge(origBB, Successors[j]);
|
||||
|
||||
if (!newBB) {
|
||||
|
||||
@ -583,6 +688,13 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (documentFile) {
|
||||
|
||||
fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n",
|
||||
moduleID, F.getName().str().c_str(), afl_global_id);
|
||||
|
||||
}
|
||||
|
||||
BasicBlock::iterator IP = newBB->getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
|
||||
@ -615,7 +727,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
if (skip_nozero) {
|
||||
if (skip_nozero == NULL) {
|
||||
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
@ -638,6 +750,9 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (documentFile) fclose(documentFile);
|
||||
documentFile = NULL;
|
||||
|
||||
// save highest location ID to global variable
|
||||
// do this after each function to fail faster
|
||||
if (!be_quiet && afl_global_id > MAP_SIZE &&
|
||||
|
@ -59,39 +59,9 @@ class AFLcheckIfInstrument : public ModulePass {
|
||||
static char ID;
|
||||
AFLcheckIfInstrument() : ModulePass(ID) {
|
||||
|
||||
int entries = 0;
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE");
|
||||
if (!instrumentListFilename)
|
||||
instrumentListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||
if (instrumentListFilename) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instrumentListFilename);
|
||||
if (!fileStream)
|
||||
report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
myInstrumentList.push_back(line);
|
||||
getline(fileStream, line);
|
||||
entries++;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
PFATAL(
|
||||
"afl-llvm-lto-instrumentlist.so loaded without "
|
||||
"AFL_LLVM_INSTRUMENT_FILE?!");
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"loaded the instrument file list %s with %d entries\n",
|
||||
instrumentListFilename, entries);
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
@ -104,7 +74,6 @@ class AFLcheckIfInstrument : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myInstrumentList;
|
||||
int debug = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -116,7 +85,6 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
|
||||
|
||||
/* Show a banner */
|
||||
|
||||
char be_quiet = 0;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
@ -131,102 +99,28 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
|
||||
for (auto &F : M) {
|
||||
|
||||
if (F.size() < 1) continue;
|
||||
|
||||
// fprintf(stderr, "F:%s\n", F.getName().str().c_str());
|
||||
if (isIgnoreFunction(&F)) continue;
|
||||
|
||||
BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
if (isInInstrumentList(&F)) {
|
||||
|
||||
if (!myInstrumentList.empty()) {
|
||||
|
||||
bool instrumentFunction = false;
|
||||
|
||||
/* Get the current location using debug information.
|
||||
* For now, just instrument the block if we are not able
|
||||
* to determine our location. */
|
||||
DebugLoc Loc = IP->getDebugLoc();
|
||||
if (Loc) {
|
||||
|
||||
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||
|
||||
unsigned int instLine = cDILoc->getLine();
|
||||
StringRef instFilename = cDILoc->getFilename();
|
||||
|
||||
if (instFilename.str().empty()) {
|
||||
|
||||
/* If the original location is empty, try using the inlined location
|
||||
*/
|
||||
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||
if (oDILoc) {
|
||||
|
||||
instFilename = oDILoc->getFilename();
|
||||
instLine = oDILoc->getLine();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(void)instLine;
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "function %s is in file %s\n",
|
||||
F.getName().str().c_str(), instFilename.str().c_str());
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myInstrumentList.begin();
|
||||
it != myInstrumentList.end(); ++it) {
|
||||
|
||||
/* We don't check for filename equality here because
|
||||
* filenames might actually be full paths. Instead we
|
||||
* check that the actual filename ends in the filename
|
||||
* specified in the list. */
|
||||
if (instFilename.str().length() >= it->length()) {
|
||||
|
||||
if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
|
||||
0) {
|
||||
|
||||
instrumentFunction = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Either we couldn't figure out our location or the location is
|
||||
* not the instrument file listed, so we skip instrumentation.
|
||||
* We do this by renaming the function. */
|
||||
if (instrumentFunction == true) {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
} else {
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"function %s is NOT in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
auto & Ctx = F.getContext();
|
||||
AttributeList Attrs = F.getAttributes();
|
||||
AttrBuilder NewAttrs;
|
||||
NewAttrs.addAttribute("skipinstrument");
|
||||
F.setAttributes(
|
||||
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
|
||||
|
||||
}
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
} else {
|
||||
|
||||
PFATAL("InstrumentList is empty");
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"function %s is NOT in the instrument file list\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
auto & Ctx = F.getContext();
|
||||
AttributeList Attrs = F.getAttributes();
|
||||
AttrBuilder NewAttrs;
|
||||
NewAttrs.addAttribute("skipinstrument");
|
||||
F.setAttributes(
|
||||
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
|
||||
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,6 @@ class AFLCoverage : public ModulePass {
|
||||
|
||||
protected:
|
||||
uint32_t ngram_size = 0;
|
||||
uint32_t debug = 0;
|
||||
uint32_t map_size = MAP_SIZE;
|
||||
uint32_t function_minimum_size = 1;
|
||||
char * ctx_str = NULL, *skip_nozero = NULL;
|
||||
@ -113,7 +112,7 @@ uint64_t PowerOf2Ceil(unsigned in) {
|
||||
#endif
|
||||
|
||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
#if LLVM_VERSION_MAJOR > 4 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
@ -139,7 +138,6 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
/* Show a banner */
|
||||
|
||||
char be_quiet = 0;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
@ -196,7 +194,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* Decide previous location vector size (must be a power of two) */
|
||||
VectorType *PrevLocTy;
|
||||
VectorType *PrevLocTy = NULL;
|
||||
|
||||
if (ngram_size_str)
|
||||
if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
|
||||
@ -238,7 +236,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
|
||||
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
|
||||
GlobalVariable *AFLPrevLoc;
|
||||
GlobalVariable *AFLContext;
|
||||
GlobalVariable *AFLContext = NULL;
|
||||
|
||||
if (ctx_str)
|
||||
#ifdef __ANDROID__
|
||||
@ -294,11 +292,12 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
|
||||
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
|
||||
|
||||
LoadInst *PrevCtx; // CTX sensitive coverage
|
||||
LoadInst *PrevCtx = NULL; // CTX sensitive coverage
|
||||
|
||||
/* Instrument all the things! */
|
||||
|
||||
int inst_blocks = 0;
|
||||
scanForDangerousFunctions(&M);
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
@ -42,6 +44,8 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include "snapshot-inl.h"
|
||||
#endif
|
||||
@ -50,12 +54,16 @@
|
||||
Basically, we need to make sure that the forkserver is initialized after
|
||||
the LLVM-generated runtime initialization pass, not before. */
|
||||
|
||||
#define CONST_PRIO 5
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#define MAP_FIXED_NOREPLACE MAP_FIXED
|
||||
#ifdef MAP_EXCL
|
||||
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
|
||||
#else
|
||||
#define MAP_FIXED_NOREPLACE MAP_FIXED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CTOR_PRIO 3
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@ -69,11 +77,7 @@
|
||||
#define MAP_INITIAL_SIZE MAP_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef AFL_REAL_LD
|
||||
u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
||||
#else
|
||||
u8 __afl_area_initial[MAP_SIZE];
|
||||
#endif
|
||||
u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
||||
u8 * __afl_area_ptr = __afl_area_initial;
|
||||
u8 * __afl_dictionary;
|
||||
u8 * __afl_fuzz_ptr;
|
||||
@ -103,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) {
|
||||
@ -179,14 +187,17 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
// we we are not running in afl ensure the map exists
|
||||
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_initial; }
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
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;
|
||||
@ -196,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);
|
||||
@ -209,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);
|
||||
|
||||
}
|
||||
|
||||
@ -228,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;
|
||||
@ -303,11 +329,14 @@ 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",
|
||||
@ -316,14 +345,25 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
} 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);
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
fprintf(stderr, "DEBUG: cmplog id_str %s\n",
|
||||
id_str == NULL ? "<null>" : id_str);
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
@ -395,9 +435,12 @@ static void __afl_start_snapshots(void) {
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
|
||||
|
||||
}
|
||||
|
||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
|
||||
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||
|
||||
@ -510,12 +553,19 @@ static void __afl_start_snapshots(void) {
|
||||
|
||||
if (!child_pid) {
|
||||
|
||||
//(void)nice(-20); // does not seem to improve
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (!afl_snapshot_do()) { raise(SIGSTOP); }
|
||||
if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS |
|
||||
AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) {
|
||||
|
||||
raise(SIGSTOP);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||
@ -597,9 +647,12 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
|
||||
|
||||
}
|
||||
|
||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
|
||||
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||
|
||||
@ -713,6 +766,8 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
if (!child_pid) {
|
||||
|
||||
//(void)nice(-20);
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
@ -815,9 +870,22 @@ void __afl_manual_init(void) {
|
||||
|
||||
static u8 init_done;
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
|
||||
|
||||
init_done = 1;
|
||||
is_persistent = 0;
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_initial;
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
fprintf(stderr,
|
||||
"DEBUG: disabled instrumentation because of "
|
||||
"AFL_DISABLE_LLVM_INSTRUMENTATION\n");
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_map_shm();
|
||||
__afl_start_forkserver();
|
||||
init_done = 1;
|
||||
|
||||
@ -825,11 +893,11 @@ void __afl_manual_init(void) {
|
||||
|
||||
}
|
||||
|
||||
/* Proper initialization routine. */
|
||||
/* Initialization of the forkserver - latest possible */
|
||||
|
||||
__attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
|
||||
__attribute__((constructor())) void __afl_auto_init(void) {
|
||||
|
||||
is_persistent = !!getenv(PERSIST_ENV_VAR);
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
|
||||
if (getenv(DEFER_ENV_VAR)) return;
|
||||
|
||||
@ -837,6 +905,57 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
|
||||
|
||||
}
|
||||
|
||||
/* Initialization of the shmem - earliest possible because of LTO fixed mem. */
|
||||
|
||||
__attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
|
||||
|
||||
is_persistent = !!getenv(PERSIST_ENV_VAR);
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
|
||||
__afl_map_shm();
|
||||
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
ptr = (u8 *)malloc(1024000);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
|
||||
|
||||
}
|
||||
|
||||
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
|
||||
It remains non-operational in the traditional, plugin-backed LLVM mode.
|
||||
For more info about 'trace-pc-guard', see llvm_mode/README.md.
|
||||
@ -846,8 +965,50 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
|
||||
|
||||
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
|
||||
|
||||
// For stability analysis, if you want to know to which function unstable
|
||||
// edge IDs belong - uncomment, recompile+install llvm_mode, recompile
|
||||
// the target. libunwind and libbacktrace are better solutions.
|
||||
// Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture
|
||||
// the backtrace output
|
||||
/*
|
||||
uint32_t unstable[] = { ... unstable edge IDs };
|
||||
uint32_t idx;
|
||||
char bt[1024];
|
||||
for (idx = 0; i < sizeof(unstable)/sizeof(uint32_t); i++) {
|
||||
|
||||
if (unstable[idx] == __afl_area_ptr[*guard]) {
|
||||
|
||||
int bt_size = backtrace(bt, 256);
|
||||
if (bt_size > 0) {
|
||||
|
||||
char **bt_syms = backtrace_symbols(bt, bt_size);
|
||||
if (bt_syms) {
|
||||
|
||||
fprintf(stderr, "DEBUG: edge=%u caller=%s\n", unstable[idx],
|
||||
bt_syms[0]);
|
||||
free(bt_syms);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#if (LLVM_VERSION_MAJOR < 9)
|
||||
|
||||
__afl_area_ptr[*guard]++;
|
||||
|
||||
#else
|
||||
|
||||
__afl_area_ptr[*guard] =
|
||||
__afl_area_ptr[*guard] + 1 + (__afl_area_ptr[*guard] == 255 ? 1 : 0);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Init callback. Populates instrumentation IDs. Note that we're using
|
||||
@ -859,6 +1020,15 @@ 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",
|
||||
start, stop);
|
||||
|
||||
}
|
||||
|
||||
if (start == stop || *start) return;
|
||||
|
||||
x = getenv("AFL_INST_RATIO");
|
||||
@ -894,7 +1064,7 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
@ -917,7 +1087,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
|
||||
|
||||
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
@ -938,7 +1108,7 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
|
||||
|
||||
void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
@ -959,7 +1129,7 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
|
||||
|
||||
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
@ -1010,6 +1180,8 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
for (uint64_t i = 0; i < cases[0]; i++) {
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0) + i;
|
||||
@ -1047,7 +1219,7 @@ static int area_is_mapped(void *ptr, size_t len) {
|
||||
|
||||
void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
|
||||
|
@ -76,9 +76,6 @@ class CmpLogInstructions : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M);
|
||||
|
||||
@ -287,3 +284,9 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPass(
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmpLogInstructionsPass);
|
||||
#endif
|
||||
|
||||
|
@ -76,9 +76,6 @@ class CmpLogRoutines : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool hookRtns(Module &M);
|
||||
|
||||
@ -207,3 +204,9 @@ static RegisterStandardPasses RegisterCmpLogRoutinesPass(
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmpLogRoutinesPass);
|
||||
#endif
|
||||
|
||||
|
@ -75,9 +75,6 @@ class CompareTransform : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool transformCmps(Module &M, const bool processStrcmp,
|
||||
const bool processMemcmp, const bool processStrncmp,
|
||||
@ -140,7 +137,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
bool isStrcasecmp = processStrcasecmp;
|
||||
bool isStrncasecmp = processStrncasecmp;
|
||||
bool isIntMemcpy = true;
|
||||
bool indirect = false;
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
@ -267,8 +263,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
}
|
||||
|
||||
if ((HasStr1 || HasStr2)) indirect = true;
|
||||
|
||||
}
|
||||
|
||||
if (isIntMemcpy) continue;
|
||||
@ -281,7 +275,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
Str1 = StringRef(*val);
|
||||
HasStr1 = true;
|
||||
indirect = true;
|
||||
// fprintf(stderr, "loaded1 %s\n", Str1.str().c_str());
|
||||
|
||||
} else {
|
||||
@ -291,7 +284,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
Str2 = StringRef(*val);
|
||||
HasStr2 = true;
|
||||
indirect = true;
|
||||
// fprintf(stderr, "loaded2 %s\n", Str2.str().c_str());
|
||||
|
||||
}
|
||||
@ -358,7 +350,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
Value * VarStr;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
uint64_t constStrLen, constSizedLen, unrollLen;
|
||||
uint64_t constStrLen, unrollLen, constSizedLen = 0;
|
||||
bool isMemcmp =
|
||||
!callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
|
||||
bool isSizedcmp = isMemcmp ||
|
||||
@ -474,8 +466,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
if (cur_lenchk_bb) {
|
||||
|
||||
IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
|
||||
Value * icmp = cur_lenchk_IRB.CreateICmpEQ(sizedValue,
|
||||
ConstantInt::get(Int64Ty, i));
|
||||
Value * icmp = cur_lenchk_IRB.CreateICmpEQ(
|
||||
sizedValue, ConstantInt::get(sizedValue->getType(), i));
|
||||
cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
|
||||
cur_lenchk_bb->getTerminator()->eraseFromParent();
|
||||
|
||||
@ -588,3 +580,8 @@ static RegisterStandardPasses RegisterCompTransPass(
|
||||
static RegisterStandardPasses RegisterCompTransPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCompTransPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass);
|
||||
#endif
|
||||
|
||||
|
@ -71,15 +71,13 @@ class SplitComparesTransform : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
int enableFPSplit;
|
||||
|
||||
size_t splitIntCompares(Module &M, unsigned bitw);
|
||||
size_t splitFPCompares(Module &M);
|
||||
bool simplifyCompares(Module &M);
|
||||
bool simplifyFPCompares(Module &M);
|
||||
bool simplifyIntSignedness(Module &M);
|
||||
size_t nextPowerOfTwo(size_t in);
|
||||
|
||||
@ -89,13 +87,143 @@ class SplitComparesTransform : public ModulePass {
|
||||
|
||||
char SplitComparesTransform::ID = 0;
|
||||
|
||||
/* This function splits FCMP instructions with xGE or xLE predicates into two
|
||||
* FCMP instructions with predicate xGT or xLT and EQ */
|
||||
bool SplitComparesTransform::simplifyFPCompares(Module &M) {
|
||||
|
||||
LLVMContext & C = M.getContext();
|
||||
std::vector<Instruction *> fcomps;
|
||||
IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add
|
||||
* all integer comparisons with >= and <= predicates to the icomps vector */
|
||||
for (auto &F : M) {
|
||||
|
||||
if (!isInInstrumentList(&F)) continue;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CmpInst *selectcmpInst = nullptr;
|
||||
|
||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
if (enableFPSplit &&
|
||||
(selectcmpInst->getPredicate() == CmpInst::FCMP_OGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_OLE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) {
|
||||
|
||||
auto op0 = selectcmpInst->getOperand(0);
|
||||
auto op1 = selectcmpInst->getOperand(1);
|
||||
|
||||
Type *TyOp0 = op0->getType();
|
||||
Type *TyOp1 = op1->getType();
|
||||
|
||||
/* this is probably not needed but we do it anyway */
|
||||
if (TyOp0 != TyOp1) { continue; }
|
||||
|
||||
if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; }
|
||||
|
||||
fcomps.push_back(selectcmpInst);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!fcomps.size()) { return false; }
|
||||
|
||||
/* transform for floating point */
|
||||
for (auto &FcmpInst : fcomps) {
|
||||
|
||||
BasicBlock *bb = FcmpInst->getParent();
|
||||
|
||||
auto op0 = FcmpInst->getOperand(0);
|
||||
auto op1 = FcmpInst->getOperand(1);
|
||||
|
||||
/* find out what the new predicate is going to be */
|
||||
auto pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate();
|
||||
CmpInst::Predicate new_pred;
|
||||
switch (pred) {
|
||||
|
||||
case CmpInst::FCMP_UGE:
|
||||
new_pred = CmpInst::FCMP_UGT;
|
||||
break;
|
||||
case CmpInst::FCMP_OGE:
|
||||
new_pred = CmpInst::FCMP_OGT;
|
||||
break;
|
||||
case CmpInst::FCMP_ULE:
|
||||
new_pred = CmpInst::FCMP_ULT;
|
||||
break;
|
||||
case CmpInst::FCMP_OLE:
|
||||
new_pred = CmpInst::FCMP_OLT;
|
||||
break;
|
||||
default: // keep the compiler happy
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* split before the fcmp instruction */
|
||||
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
|
||||
|
||||
/* the old bb now contains a unconditional jump to the new one (end_bb)
|
||||
* we need to delete it later */
|
||||
|
||||
/* create the FCMP instruction with new_pred and add it to the old basic
|
||||
* block bb it is now at the position where the old FcmpInst was */
|
||||
Instruction *fcmp_np;
|
||||
fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
|
||||
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
|
||||
fcmp_np);
|
||||
|
||||
/* create a new basic block which holds the new EQ fcmp */
|
||||
Instruction *fcmp_eq;
|
||||
/* insert middle_bb before end_bb */
|
||||
BasicBlock *middle_bb =
|
||||
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
|
||||
fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
|
||||
middle_bb->getInstList().push_back(fcmp_eq);
|
||||
/* add an unconditional branch to the end of middle_bb with destination
|
||||
* end_bb */
|
||||
BranchInst::Create(end_bb, middle_bb);
|
||||
|
||||
/* replace the uncond branch with a conditional one, which depends on the
|
||||
* new_pred fcmp. True goes to end, false to the middle (injected) bb */
|
||||
auto term = bb->getTerminator();
|
||||
BranchInst::Create(end_bb, middle_bb, fcmp_np, bb);
|
||||
term->eraseFromParent();
|
||||
|
||||
/* replace the old FcmpInst (which is the first inst in end_bb) with a PHI
|
||||
* inst to wire up the loose ends */
|
||||
PHINode *PN = PHINode::Create(Int1Ty, 2, "");
|
||||
/* the first result depends on the outcome of fcmp_eq */
|
||||
PN->addIncoming(fcmp_eq, middle_bb);
|
||||
/* if the source was the original bb we know that the fcmp_np yielded true
|
||||
* hence we can hardcode this value */
|
||||
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
|
||||
/* replace the old FcmpInst with our new and shiny PHI inst */
|
||||
BasicBlock::iterator ii(FcmpInst);
|
||||
ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* This function splits ICMP instructions with xGE or xLE predicates into two
|
||||
* ICMP instructions with predicate xGT or xLT and EQ */
|
||||
bool SplitComparesTransform::simplifyCompares(Module &M) {
|
||||
|
||||
LLVMContext & C = M.getContext();
|
||||
std::vector<Instruction *> icomps;
|
||||
std::vector<Instruction *> fcomps;
|
||||
IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add
|
||||
@ -130,27 +258,6 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (enableFPSplit &&
|
||||
(selectcmpInst->getPredicate() == CmpInst::FCMP_OGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_OLE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) {
|
||||
|
||||
auto op0 = selectcmpInst->getOperand(0);
|
||||
auto op1 = selectcmpInst->getOperand(1);
|
||||
|
||||
Type *TyOp0 = op0->getType();
|
||||
Type *TyOp1 = op1->getType();
|
||||
|
||||
/* this is probably not needed but we do it anyway */
|
||||
if (TyOp0 != TyOp1) { continue; }
|
||||
|
||||
if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; }
|
||||
|
||||
fcomps.push_back(selectcmpInst);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -159,7 +266,7 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (!icomps.size() && !fcomps.size()) { return false; }
|
||||
if (!icomps.size()) { return false; }
|
||||
|
||||
for (auto &IcmpInst : icomps) {
|
||||
|
||||
@ -234,80 +341,6 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
/* now for floating point */
|
||||
for (auto &FcmpInst : fcomps) {
|
||||
|
||||
BasicBlock *bb = FcmpInst->getParent();
|
||||
|
||||
auto op0 = FcmpInst->getOperand(0);
|
||||
auto op1 = FcmpInst->getOperand(1);
|
||||
|
||||
/* find out what the new predicate is going to be */
|
||||
auto pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate();
|
||||
CmpInst::Predicate new_pred;
|
||||
switch (pred) {
|
||||
|
||||
case CmpInst::FCMP_UGE:
|
||||
new_pred = CmpInst::FCMP_UGT;
|
||||
break;
|
||||
case CmpInst::FCMP_OGE:
|
||||
new_pred = CmpInst::FCMP_OGT;
|
||||
break;
|
||||
case CmpInst::FCMP_ULE:
|
||||
new_pred = CmpInst::FCMP_ULT;
|
||||
break;
|
||||
case CmpInst::FCMP_OLE:
|
||||
new_pred = CmpInst::FCMP_OLT;
|
||||
break;
|
||||
default: // keep the compiler happy
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* split before the icmp instruction */
|
||||
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
|
||||
|
||||
/* the old bb now contains a unconditional jump to the new one (end_bb)
|
||||
* we need to delete it later */
|
||||
|
||||
/* create the ICMP instruction with new_pred and add it to the old basic
|
||||
* block bb it is now at the position where the old IcmpInst was */
|
||||
Instruction *fcmp_np;
|
||||
fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
|
||||
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
|
||||
fcmp_np);
|
||||
|
||||
/* create a new basic block which holds the new EQ fcmp */
|
||||
Instruction *fcmp_eq;
|
||||
/* insert middle_bb before end_bb */
|
||||
BasicBlock *middle_bb =
|
||||
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
|
||||
fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
|
||||
middle_bb->getInstList().push_back(fcmp_eq);
|
||||
/* add an unconditional branch to the end of middle_bb with destination
|
||||
* end_bb */
|
||||
BranchInst::Create(end_bb, middle_bb);
|
||||
|
||||
/* replace the uncond branch with a conditional one, which depends on the
|
||||
* new_pred icmp. True goes to end, false to the middle (injected) bb */
|
||||
auto term = bb->getTerminator();
|
||||
BranchInst::Create(end_bb, middle_bb, fcmp_np, bb);
|
||||
term->eraseFromParent();
|
||||
|
||||
/* replace the old IcmpInst (which is the first inst in end_bb) with a PHI
|
||||
* inst to wire up the loose ends */
|
||||
PHINode *PN = PHINode::Create(Int1Ty, 2, "");
|
||||
/* the first result depends on the outcome of icmp_eq */
|
||||
PN->addIncoming(fcmp_eq, middle_bb);
|
||||
/* if the source was the original bb we know that the icmp_np yielded true
|
||||
* hence we can hardcode this value */
|
||||
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
|
||||
/* replace the old IcmpInst with our new and shiny PHI inst */
|
||||
BasicBlock::iterator ii(FcmpInst);
|
||||
ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -640,7 +673,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
BranchInst::Create(end_bb, signequal_bb);
|
||||
|
||||
/* create a new bb which is executed if exponents are equal */
|
||||
/* create a new bb which is executed if exponents are satisfying the compare
|
||||
*/
|
||||
BasicBlock *middle_bb =
|
||||
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
|
||||
|
||||
@ -695,7 +729,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
}
|
||||
|
||||
/* compare the exponents of the operands */
|
||||
Instruction *icmp_exponents_equal;
|
||||
Instruction *icmp_exponent_result;
|
||||
BasicBlock * signequal2_bb = signequal_bb;
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_OEQ:
|
||||
@ -707,22 +743,60 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
icmp_exponent_result =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, m_e0, m_e1);
|
||||
break;
|
||||
/* compare the exponents of the operands (signs are equal)
|
||||
* if exponents are equal -> proceed to mantissa comparison
|
||||
* else get result depending on sign
|
||||
*/
|
||||
case CmpInst::FCMP_OGT:
|
||||
case CmpInst::FCMP_UGT:
|
||||
Instruction *icmp_exponent;
|
||||
icmp_exponents_equal =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
|
||||
signequal_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()),
|
||||
icmp_exponents_equal);
|
||||
|
||||
// shortcut for unequal exponents
|
||||
signequal2_bb = signequal_bb->splitBasicBlock(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()));
|
||||
|
||||
/* if the exponents are equal goto middle_bb else to signequal2_bb */
|
||||
term = signequal_bb->getTerminator();
|
||||
BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
|
||||
signequal_bb);
|
||||
term->eraseFromParent();
|
||||
|
||||
icmp_exponent =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1);
|
||||
signequal_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent);
|
||||
signequal2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal2_bb->getTerminator()),
|
||||
icmp_exponent);
|
||||
icmp_exponent_result =
|
||||
BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
|
||||
break;
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT:
|
||||
icmp_exponents_equal =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
|
||||
signequal_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()),
|
||||
icmp_exponents_equal);
|
||||
|
||||
// shortcut for unequal exponents
|
||||
signequal2_bb = signequal_bb->splitBasicBlock(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()));
|
||||
|
||||
/* if the exponents are equal goto middle_bb else to signequal2_bb */
|
||||
term = signequal_bb->getTerminator();
|
||||
BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
|
||||
signequal_bb);
|
||||
term->eraseFromParent();
|
||||
|
||||
icmp_exponent =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1);
|
||||
signequal_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent);
|
||||
signequal2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal2_bb->getTerminator()),
|
||||
icmp_exponent);
|
||||
icmp_exponent_result =
|
||||
BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
|
||||
break;
|
||||
@ -731,15 +805,40 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
signequal_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal_bb->getTerminator()),
|
||||
signequal2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(signequal2_bb->getTerminator()),
|
||||
icmp_exponent_result);
|
||||
|
||||
{
|
||||
|
||||
auto term = signequal_bb->getTerminator();
|
||||
/* if the exponents are different do a fraction cmp */
|
||||
BranchInst::Create(middle_bb, end_bb, icmp_exponent_result, signequal_bb);
|
||||
term = signequal2_bb->getTerminator();
|
||||
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_OEQ:
|
||||
/* if the exponents are satifying the compare do a fraction cmp in
|
||||
* middle_bb */
|
||||
BranchInst::Create(middle_bb, end_bb, icmp_exponent_result,
|
||||
signequal2_bb);
|
||||
break;
|
||||
case CmpInst::FCMP_ONE:
|
||||
case CmpInst::FCMP_UNE:
|
||||
/* if the exponents are satifying the compare do a fraction cmp in
|
||||
* middle_bb */
|
||||
BranchInst::Create(end_bb, middle_bb, icmp_exponent_result,
|
||||
signequal2_bb);
|
||||
break;
|
||||
case CmpInst::FCMP_OGT:
|
||||
case CmpInst::FCMP_UGT:
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT:
|
||||
BranchInst::Create(end_bb, signequal2_bb);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
term->eraseFromParent();
|
||||
|
||||
}
|
||||
@ -800,44 +899,82 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
/* compare the fractions of the operands */
|
||||
Instruction *icmp_fraction_result;
|
||||
Instruction *icmp_fraction_result2;
|
||||
BasicBlock * middle2_bb = middle_bb;
|
||||
PHINode * PN2 = nullptr;
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_OEQ:
|
||||
icmp_fraction_result =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
|
||||
middle2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle2_bb->getTerminator()),
|
||||
icmp_fraction_result);
|
||||
|
||||
break;
|
||||
case CmpInst::FCMP_UNE:
|
||||
case CmpInst::FCMP_ONE:
|
||||
icmp_fraction_result =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1);
|
||||
middle2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle2_bb->getTerminator()),
|
||||
icmp_fraction_result);
|
||||
|
||||
break;
|
||||
case CmpInst::FCMP_OGT:
|
||||
case CmpInst::FCMP_UGT:
|
||||
Instruction *icmp_fraction;
|
||||
icmp_fraction =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1);
|
||||
middle_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction);
|
||||
icmp_fraction_result =
|
||||
BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0);
|
||||
break;
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT:
|
||||
icmp_fraction =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1);
|
||||
middle_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction);
|
||||
icmp_fraction_result =
|
||||
BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0);
|
||||
break;
|
||||
case CmpInst::FCMP_ULT: {
|
||||
|
||||
middle2_bb = middle_bb->splitBasicBlock(
|
||||
BasicBlock::iterator(middle_bb->getTerminator()));
|
||||
|
||||
BasicBlock *negative_bb = BasicBlock::Create(
|
||||
C, "negative_value", middle2_bb->getParent(), middle2_bb);
|
||||
BasicBlock *positive_bb = BasicBlock::Create(
|
||||
C, "positive_value", negative_bb->getParent(), negative_bb);
|
||||
|
||||
if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT ||
|
||||
FcmpInst->getPredicate() == CmpInst::FCMP_UGT) {
|
||||
|
||||
negative_bb->getInstList().push_back(
|
||||
icmp_fraction_result = CmpInst::Create(
|
||||
Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
|
||||
positive_bb->getInstList().push_back(
|
||||
icmp_fraction_result2 = CmpInst::Create(
|
||||
Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
|
||||
|
||||
} else {
|
||||
|
||||
negative_bb->getInstList().push_back(
|
||||
icmp_fraction_result = CmpInst::Create(
|
||||
Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
|
||||
positive_bb->getInstList().push_back(
|
||||
icmp_fraction_result2 = CmpInst::Create(
|
||||
Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
|
||||
|
||||
}
|
||||
|
||||
BranchInst::Create(middle2_bb, negative_bb);
|
||||
BranchInst::Create(middle2_bb, positive_bb);
|
||||
|
||||
term = middle_bb->getTerminator();
|
||||
BranchInst::Create(negative_bb, positive_bb, t_s0, middle_bb);
|
||||
term->eraseFromParent();
|
||||
|
||||
PN2 = PHINode::Create(Int1Ty, 2, "");
|
||||
PN2->addIncoming(icmp_fraction_result, negative_bb);
|
||||
PN2->addIncoming(icmp_fraction_result2, positive_bb);
|
||||
middle2_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle2_bb->getTerminator()), PN2);
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
middle_bb->getInstList().insert(
|
||||
BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction_result);
|
||||
|
||||
PHINode *PN = PHINode::Create(Int1Ty, 3, "");
|
||||
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
@ -849,7 +986,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
/* unequal exponents cannot be equal values, too */
|
||||
PN->addIncoming(ConstantInt::get(Int1Ty, 0), signequal_bb);
|
||||
/* fractions comparison */
|
||||
PN->addIncoming(icmp_fraction_result, middle_bb);
|
||||
PN->addIncoming(icmp_fraction_result, middle2_bb);
|
||||
break;
|
||||
case CmpInst::FCMP_ONE:
|
||||
case CmpInst::FCMP_UNE:
|
||||
@ -857,25 +994,25 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
/* goto true branch */
|
||||
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
|
||||
/* unequal exponents are unequal values, too */
|
||||
PN->addIncoming(ConstantInt::get(Int1Ty, 1), signequal_bb);
|
||||
PN->addIncoming(icmp_exponent_result, signequal_bb);
|
||||
/* fractions comparison */
|
||||
PN->addIncoming(icmp_fraction_result, middle_bb);
|
||||
PN->addIncoming(icmp_fraction_result, middle2_bb);
|
||||
break;
|
||||
case CmpInst::FCMP_OGT:
|
||||
case CmpInst::FCMP_UGT:
|
||||
/* if op1 is negative goto true branch,
|
||||
else go on comparing */
|
||||
PN->addIncoming(t_s1, bb);
|
||||
PN->addIncoming(icmp_exponent_result, signequal_bb);
|
||||
PN->addIncoming(icmp_fraction_result, middle_bb);
|
||||
PN->addIncoming(icmp_exponent_result, signequal2_bb);
|
||||
PN->addIncoming(PN2, middle2_bb);
|
||||
break;
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT:
|
||||
/* if op0 is negative goto true branch,
|
||||
else go on comparing */
|
||||
PN->addIncoming(t_s0, bb);
|
||||
PN->addIncoming(icmp_exponent_result, signequal_bb);
|
||||
PN->addIncoming(icmp_fraction_result, middle_bb);
|
||||
PN->addIncoming(icmp_exponent_result, signequal2_bb);
|
||||
PN->addIncoming(PN2, middle2_bb);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@ -1107,7 +1244,8 @@ size_t SplitComparesTransform::splitIntCompares(Module &M, unsigned bitw) {
|
||||
|
||||
bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
int bitw = 64;
|
||||
int bitw = 64;
|
||||
size_t count;
|
||||
|
||||
char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
|
||||
if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
|
||||
@ -1115,30 +1253,44 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL;
|
||||
|
||||
simplifyCompares(M);
|
||||
|
||||
simplifyIntSignedness(M);
|
||||
|
||||
if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
|
||||
getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
errs() << "Split-compare-pass by laf.intel@gmail.com, extended by "
|
||||
"heiko@hexco.de\n";
|
||||
|
||||
if (enableFPSplit)
|
||||
errs() << "Split-floatingpoint-compare-pass: " << splitFPCompares(M)
|
||||
<< " FP comparisons splitted\n";
|
||||
|
||||
} else
|
||||
} else {
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
}
|
||||
|
||||
if (enableFPSplit) {
|
||||
|
||||
count = splitFPCompares(M);
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
errs() << "Split-floatingpoint-compare-pass: " << count
|
||||
<< " FP comparisons splitted\n";
|
||||
|
||||
}
|
||||
|
||||
simplifyFPCompares(M);
|
||||
|
||||
}
|
||||
|
||||
simplifyCompares(M);
|
||||
|
||||
simplifyIntSignedness(M);
|
||||
|
||||
switch (bitw) {
|
||||
|
||||
case 64:
|
||||
count = splitIntCompares(M, bitw);
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " splitted\n";
|
||||
|
||||
bitw >>= 1;
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
@ -1146,9 +1298,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
|
||||
#endif
|
||||
case 32:
|
||||
count = splitIntCompares(M, bitw);
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " splitted\n";
|
||||
|
||||
bitw >>= 1;
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
@ -1156,9 +1309,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
|
||||
#endif
|
||||
case 16:
|
||||
count = splitIntCompares(M, bitw);
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " splitted\n";
|
||||
|
||||
bitw >>= 1;
|
||||
break;
|
||||
@ -1188,3 +1342,9 @@ static RegisterStandardPasses RegisterSplitComparesPass(
|
||||
static RegisterStandardPasses RegisterSplitComparesTransPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerSplitComparesPass);
|
||||
#endif
|
||||
|
||||
|
@ -91,9 +91,6 @@ class SplitSwitchesTransform : public ModulePass {
|
||||
|
||||
typedef std::vector<CaseExpr> CaseVector;
|
||||
|
||||
protected:
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool splitSwitches(Module &M);
|
||||
bool transformCmps(Module &M, const bool processStrcmp,
|
||||
@ -442,3 +439,9 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass(
|
||||
static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerSplitSwitchesTransPass);
|
||||
#endif
|
||||
|
||||
|
@ -176,6 +176,7 @@ echo Building for CPU target $CPU_TARGET
|
||||
echo "[*] Applying patches..."
|
||||
|
||||
patch -p1 <../patches/elfload.diff || exit 1
|
||||
patch -p1 <../patches/mips-fpu.diff || exit 1
|
||||
patch -p1 <../patches/bsd-elfload.diff || exit 1
|
||||
patch -p1 <../patches/cpu-exec.diff || exit 1
|
||||
patch -p1 <../patches/syscall.diff || exit 1
|
||||
|
@ -620,7 +620,13 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
|
||||
|
||||
last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base,
|
||||
c.last_tb.flags, c.cf_mask);
|
||||
if (last_tb) { tb_add_jump(last_tb, c.tb_exit, tb); }
|
||||
#define TB_JMP_RESET_OFFSET_INVALID 0xffff
|
||||
if (last_tb && (last_tb->jmp_reset_offset[c.tb_exit] !=
|
||||
TB_JMP_RESET_OFFSET_INVALID)) {
|
||||
|
||||
tb_add_jump(last_tb, c.tb_exit, tb);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
15
qemu_mode/patches/mips-fpu.diff
Normal file
15
qemu_mode/patches/mips-fpu.diff
Normal file
@ -0,0 +1,15 @@
|
||||
--- a/linux-user/elfload.c 2020-07-13 20:10:37.776374566 -0700
|
||||
+++ b/linux-user/elfload.c 2020-07-13 20:11:51.794957015 -0700
|
||||
@@ -2667,6 +2667,11 @@
|
||||
char *elf_interpreter = NULL;
|
||||
char *scratch;
|
||||
|
||||
+ memset(&interp_info, 0, sizeof(interp_info));
|
||||
+#ifdef TARGET_MIPS
|
||||
+ interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
|
||||
+#endif
|
||||
+
|
||||
info->start_mmap = (abi_ulong)ELF_START_MMAP;
|
||||
|
||||
load_elf_image(bprm->filename, bprm->fd, info,
|
||||
|
@ -384,7 +384,7 @@ static void show_legend(void) {
|
||||
|
||||
/* Interpret and report a pattern in the input file. */
|
||||
|
||||
static void dump_hex(u8 *buf, u32 len, u8 *b_data) {
|
||||
static void dump_hex(u32 len, u8 *b_data) {
|
||||
|
||||
u32 i;
|
||||
|
||||
@ -678,7 +678,7 @@ static void analyze(char **argv) {
|
||||
|
||||
}
|
||||
|
||||
dump_hex(in_data, in_len, b_data);
|
||||
dump_hex(in_len, b_data);
|
||||
|
||||
SAYF("\n");
|
||||
|
||||
@ -700,6 +700,7 @@ static void analyze(char **argv) {
|
||||
|
||||
static void handle_stop_sig(int sig) {
|
||||
|
||||
(void)sig;
|
||||
stop_soon = 1;
|
||||
|
||||
if (child_pid > 0) { kill(child_pid, SIGKILL); }
|
||||
@ -772,15 +773,38 @@ static void set_up_environment(void) {
|
||||
setenv("ASAN_OPTIONS",
|
||||
"abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"symbolize=0:"
|
||||
"allocator_may_return_null=1",
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0",
|
||||
0);
|
||||
|
||||
setenv("UBSAN_OPTIONS",
|
||||
"halt_on_error=1:"
|
||||
"abort_on_error=1:"
|
||||
"malloc_context_size=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"symbolize=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0",
|
||||
0);
|
||||
|
||||
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
|
||||
"symbolize=0:"
|
||||
"abort_on_error=1:"
|
||||
"msan_track_origins=0"
|
||||
"allocator_may_return_null=1:"
|
||||
"msan_track_origins=0", 0);
|
||||
"symbolize=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0", 0);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
|
10
src/afl-as.c
10
src/afl-as.c
@ -136,7 +136,7 @@ static void edit_params(int argc, char **argv) {
|
||||
|
||||
as_params[argc] = 0;
|
||||
|
||||
for (i = 1; i < argc - 1; i++) {
|
||||
for (i = 1; (s32)i < argc - 1; i++) {
|
||||
|
||||
if (!strcmp(argv[i], "--64")) {
|
||||
|
||||
@ -407,7 +407,7 @@ static void add_instrumentation(void) {
|
||||
|
||||
if (line[0] == '\t') {
|
||||
|
||||
if (line[1] == 'j' && line[2] != 'm' && R(100) < inst_ratio) {
|
||||
if (line[1] == 'j' && line[2] != 'm' && R(100) < (long)inst_ratio) {
|
||||
|
||||
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
|
||||
R(MAP_SIZE));
|
||||
@ -449,7 +449,7 @@ static void add_instrumentation(void) {
|
||||
/* Apple: L<num> / LBB<num> */
|
||||
|
||||
if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) &&
|
||||
R(100) < inst_ratio) {
|
||||
R(100) < (long)inst_ratio) {
|
||||
|
||||
#else
|
||||
|
||||
@ -457,7 +457,7 @@ static void add_instrumentation(void) {
|
||||
|
||||
if ((isdigit(line[2]) ||
|
||||
(clang_mode && !strncmp(line + 1, "LBB", 3))) &&
|
||||
R(100) < inst_ratio) {
|
||||
R(100) < (long)inst_ratio) {
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
@ -591,7 +591,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
|
||||
// in fast systems where pids can repeat in the same seconds we need this
|
||||
for (i = 1; i < argc; i++)
|
||||
for (i = 1; (s32)i < argc; i++)
|
||||
for (j = 0; j < strlen(argv[i]); j++)
|
||||
rand_seed += argv[i][j];
|
||||
|
||||
|
@ -145,7 +145,8 @@ 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 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(new_argv + 3, argv + 1, (int)(sizeof(char *)) * argc);
|
||||
memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
|
||||
new_argv[2] = *target_path_p;
|
||||
new_argv[1] = "--";
|
||||
@ -226,7 +227,8 @@ 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 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(new_argv + 2, argv + 1, (int)(sizeof(char *)) * argc);
|
||||
memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
|
||||
new_argv[1] = *target_path_p;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user