mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
513 Commits
Author | SHA1 | Date | |
---|---|---|---|
fb8da3e4b1 | |||
a9c0f9a165 | |||
4b5c4d58dc | |||
b0e58b5b14 | |||
858c81a19b | |||
04360a35ed | |||
c8ca944fac | |||
b5e4d1a491 | |||
20cb846c95 | |||
a1e531589e | |||
d6b680de48 | |||
28314632bd | |||
09ab904354 | |||
5c0cf60ec1 | |||
698caed9c0 | |||
ae05f5c4b0 | |||
d397bba6b2 | |||
7a6b66e684 | |||
e6daeef55c | |||
c36c1b8992 | |||
1d1f575b5c | |||
ecdffa03f8 | |||
6688184bfd | |||
84a4fd40a0 | |||
d37a195392 | |||
11e76af819 | |||
ed8c0d173e | |||
c57fdbedaf | |||
bd9676aa04 | |||
e5d0a9ecdf | |||
314debb799 | |||
24ad714d0d | |||
41225b53fa | |||
5efd306f7b | |||
ccbcb5c8d3 | |||
2f172d6c5a | |||
1eb81fdf36 | |||
62b6af693d | |||
a49988afbf | |||
03495beadb | |||
079fdbf9bc | |||
002e3840e6 | |||
96c558bec4 | |||
a267263420 | |||
c14fd1ad18 | |||
88782ae43c | |||
70e777d031 | |||
9e1482ad04 | |||
fef08192ad | |||
5488422471 | |||
e8e6dbf839 | |||
5602a09cc6 | |||
164a01e723 | |||
f7f106c42a | |||
7f817fe583 | |||
5e66d95fbd | |||
d064b2e4af | |||
9d067d26da | |||
8e417ecb5c | |||
a9d072ad02 | |||
5630c2e72c | |||
29ff59cc8a | |||
dab429521b | |||
48fc106905 | |||
ee72d5d01d | |||
378f4dd46d | |||
2455f081fc | |||
d40866add2 | |||
9ca8ff77f3 | |||
e95ac10ff7 | |||
c7cf2c17a2 | |||
29b1e30126 | |||
24b9eddc7e | |||
effa766d4a | |||
b9783e44a3 | |||
35c817ccd0 | |||
77d68bc7bd | |||
6392a349ce | |||
4489dd24a8 | |||
d374648ce3 | |||
d611e7d50e | |||
25d6d21617 | |||
74b4096570 | |||
eca55be4fb | |||
71372c4d2f | |||
a0693d466c | |||
14d2456c35 | |||
c8bdf0790f | |||
0b8a5cb4bb | |||
8f98d5a8f8 | |||
b83a2c1a00 | |||
5a4d4ad736 | |||
5bc6dccbbd | |||
42ee300e92 | |||
582f5103d9 | |||
abef859925 | |||
6eb79c28d1 | |||
84a096561a | |||
9a1f105869 | |||
677f2c6ca9 | |||
508230e91b | |||
9cab515e58 | |||
514036898f | |||
19415f2554 | |||
710a29a1e0 | |||
c36c34cf9e | |||
e910c224da | |||
ea95453975 | |||
61ea398612 | |||
64e1d3a975 | |||
50fc7327f2 | |||
71edae4a0f | |||
0dd8ed9171 | |||
d568559f01 | |||
1e290542bb | |||
245304f593 | |||
be441dc176 | |||
da1a0249d7 | |||
d07587885c | |||
376b45c199 | |||
b247366c4e | |||
7c383094d9 | |||
9721990507 | |||
452067ffca | |||
3ce5efc44b | |||
1e8c1a4c46 | |||
b53ec1b247 | |||
4ccfbe4e5a | |||
7698c051aa | |||
1950f09bde | |||
e41b03eb30 | |||
98545f30aa | |||
81873d97f8 | |||
cda56ca129 | |||
ab5e0703da | |||
f370ef38c4 | |||
1119a2e185 | |||
9d7ac3d99f | |||
0732e66da9 | |||
e56e2f4c18 | |||
23d9649aec | |||
738a245c3e | |||
78d73720a2 | |||
e59282fe20 | |||
9785b15ed2 | |||
8c94a3d177 | |||
5bd8aa489b | |||
e71c2937de | |||
3d6c58df53 | |||
34c090a31d | |||
762421b355 | |||
b7f3d180aa | |||
71f8cc9dd2 | |||
3c7bc6fd42 | |||
af60844aea | |||
c4c13dd235 | |||
ba4f0186dd | |||
a5c09e4c11 | |||
c7818714ac | |||
cec3d74497 | |||
10b226418c | |||
c843085a28 | |||
101c5a275f | |||
acf4b0981e | |||
98c0908185 | |||
ead3701f5b | |||
0349b0a735 | |||
11cad9fb20 | |||
7f44fec0a5 | |||
d4c8a2058d | |||
d73e63bd70 | |||
d0d5518ea8 | |||
822e75f7c2 | |||
08b6b4ec4e | |||
3253e3f315 | |||
e58e54c2db | |||
0a7dc10dd3 | |||
3914aec72f | |||
9b63fc758e | |||
d3130ace30 | |||
daa09a5fbb | |||
a249dadfb0 | |||
64e9f1f3a2 | |||
9110097e11 | |||
ac48b58184 | |||
8f5fb47082 | |||
a58382d3ff | |||
5ef8e3cf29 | |||
6544014ced | |||
3fcb3e2ed3 | |||
caebc9347f | |||
1f257c5875 | |||
e2a3de71ca | |||
57a0134b0c | |||
d9b18ec853 | |||
6c14415664 | |||
567b3985ab | |||
45561d552e | |||
fbd5bd8f37 | |||
048beb752d | |||
87621b6345 | |||
ff14dfc0fc | |||
c624831717 | |||
c697a003d1 | |||
6bdd7a1609 | |||
50a195fe59 | |||
738016952f | |||
209aa25d27 | |||
1279c935e2 | |||
28e5a8031c | |||
f4844e2c0c | |||
ef3a13fa63 | |||
699f769385 | |||
2548b657d8 | |||
02d19dafb2 | |||
78009d9d07 | |||
2aa7ddf1a8 | |||
3c142efecf | |||
23b3e3c84d | |||
8b8600fdab | |||
1938a12222 | |||
4c11ef5d20 | |||
6ac40e2cc5 | |||
5625e059e1 | |||
11767bec0e | |||
7a92bf974d | |||
fc46e9c9a0 | |||
7a752d0795 | |||
0cff53785b | |||
4ad885001a | |||
a0dec909e7 | |||
2a660b19a7 | |||
8992c44c41 | |||
53fd8fe6ea | |||
0059d16731 | |||
18bc344cf5 | |||
e04f4b3f20 | |||
5e389a0970 | |||
1141459607 | |||
02659df6ba | |||
14bd424d2a | |||
7c76b7db04 | |||
a7553eae28 | |||
5cc50bb979 | |||
932eae7343 | |||
604f122819 | |||
d6a7630fe2 | |||
fc4b03ee74 | |||
e9c7610cb7 | |||
3c3a5aa503 | |||
6d3dc83c5d | |||
89512d4e05 | |||
b1d71136b0 | |||
8cf47f2425 | |||
c75b403bb7 | |||
ae284610cf | |||
5a7d33330a | |||
12a9a1001e | |||
97a1af39f7 | |||
6832435326 | |||
62bb94c50b | |||
eeb7e12b9f | |||
f796537712 | |||
469446a02b | |||
b24ef50f7b | |||
f6466214c6 | |||
9c4d32b5b8 | |||
50be709e91 | |||
2e060f856d | |||
c9a2401983 | |||
ce58790fc0 | |||
7f3e04cbc4 | |||
3fb346fe29 | |||
36213dba7d | |||
65817144ac | |||
82432195a8 | |||
77b81e7361 | |||
83f925ccc9 | |||
39208eeb9a | |||
f32d1022bd | |||
ee9447de01 | |||
dcfc24501b | |||
e65e723e03 | |||
94e30002e7 | |||
37603272be | |||
4263519479 | |||
db302ff18b | |||
cbde30e9d4 | |||
c0fd8f4e15 | |||
d39e9ea11c | |||
5b64681867 | |||
0132657432 | |||
aac7c7d75d | |||
bd239d7e3d | |||
da1f2f3c17 | |||
7374af51d1 | |||
38fa2fe0b1 | |||
5a0cc43ee1 | |||
f08a3fedf6 | |||
5cf3426834 | |||
96736309a7 | |||
42ece199c8 | |||
54d01fec43 | |||
f8d717d195 | |||
c6db05c5ae | |||
6f78b67f03 | |||
a5af81506f | |||
087bc6daeb | |||
f18dbb0b40 | |||
6cbd0f1faf | |||
dcd9cd638b | |||
350530f664 | |||
dabce05ec6 | |||
993bf03af9 | |||
2508008b53 | |||
a0012c9e82 | |||
c63956b8ec | |||
6965797286 | |||
5a74cffa0f | |||
f21ff8bac8 | |||
5d932398df | |||
5532fc1102 | |||
60d66ebc0d | |||
29853549c3 | |||
d0b5cd64c3 | |||
cd4243b6ad | |||
cd2be88707 | |||
5b9d306cdf | |||
0fa47bb867 | |||
b22e890ec2 | |||
b6fa63abdf | |||
51a346bcbe | |||
fd9587d26e | |||
0e1d82dd9f | |||
be261b3e69 | |||
f6847b0314 | |||
eca6bdb85d | |||
a3bd1c71ca | |||
b19039ba8b | |||
94a4cc8415 | |||
2e4fda6d4c | |||
cd7e234445 | |||
a5e747af14 | |||
5060861545 | |||
992cf3dd25 | |||
1dee73cdde | |||
3aa7242925 | |||
4009f3a987 | |||
cfd451c6f3 | |||
8e07fbf636 | |||
dae249dc71 | |||
e194acdd79 | |||
287d430fcf | |||
d1d2fceed8 | |||
8cc39a3590 | |||
a57896a7ce | |||
35720304be | |||
09b2565b1b | |||
5b9335be10 | |||
9ce0617cda | |||
61ba214f19 | |||
bfe076748b | |||
070412b9c1 | |||
ccb21a745d | |||
87599de782 | |||
126d1f1cd1 | |||
7685893cdb | |||
f9f163e48f | |||
15ba6249fc | |||
f3799f94bf | |||
e77c431582 | |||
338daa1282 | |||
c616fcafe8 | |||
08fe1e2cd7 | |||
746a2a0ed0 | |||
d2787519e3 | |||
23d0cea3c9 | |||
530bd2b341 | |||
8adc2648f8 | |||
0c45918d54 | |||
288432843b | |||
684f4dd1c4 | |||
d8d89507b5 | |||
f1ef398909 | |||
66e8faaaa9 | |||
f17a3dde1a | |||
88ced831c1 | |||
cc1d6b33b1 | |||
2832cb643d | |||
cd377f3d99 | |||
0def6e3471 | |||
1148a2d0d1 | |||
38d9aedb26 | |||
1467776a3f | |||
f678731234 | |||
e04d2a6efa | |||
1136e887bd | |||
416020daef | |||
73a1b39446 | |||
253bbf3a5c | |||
782cffb130 | |||
a24352ddfd | |||
2f41663673 | |||
cdd1dd3d20 | |||
dea1dbfba4 | |||
988a32ced5 | |||
188a6f5ec5 | |||
aa4050d406 | |||
581097d58d | |||
dba3595c0a | |||
c159b872ef | |||
df74edeb45 | |||
dcf7d85cba | |||
8e953d9931 | |||
9f89bbd5ec | |||
6a6dd84b39 | |||
36ce9c1fb9 | |||
0581f6ec00 | |||
1a582d54e5 | |||
a3161b902e | |||
783f3b0957 | |||
8ff0161d58 | |||
9f7bcca91e | |||
891f6985ed | |||
98ffef26dc | |||
81179b4829 | |||
e7bc3e09a3 | |||
8f93cf5c55 | |||
dc0b2dda5e | |||
ed5d65b54f | |||
172d384bf2 | |||
1e30c3a941 | |||
a10a3f2fa7 | |||
2287534ec6 | |||
27d6d35893 | |||
13429d204d | |||
0d4f2da8db | |||
47fdbf3817 | |||
1d4a3c87f5 | |||
c18f6c2618 | |||
6e8f249b20 | |||
3ac568c40c | |||
90409f383a | |||
cc72f5dfd0 | |||
6d620f5e0c | |||
9d686ba523 | |||
9e5c4973eb | |||
70a67ca67d | |||
e43473faef | |||
38e7dd2b9e | |||
42ce48db39 | |||
445d4b7e59 | |||
05a3418f86 | |||
df46521658 | |||
d559d5a374 | |||
469b8ee022 | |||
385f7da77f | |||
90506479e7 | |||
b2a2b0fc21 | |||
7862416844 | |||
031946136b | |||
7b59e05600 | |||
f6050ab804 | |||
43e97a5aa2 | |||
f0cf9c2cdf | |||
3e0a3ec45f | |||
6865cd8d69 | |||
59b80cb01e | |||
d946be29b9 | |||
95322c11d9 | |||
76ca6adbc5 | |||
45aa579f68 | |||
9ddd7e0e3f | |||
6730b6a15a | |||
6e08be1d0b | |||
0b21441590 | |||
449a14d1d0 | |||
57495a794d | |||
7d0ae2939d | |||
7fa289316a | |||
0e8388d3ea | |||
caa8fea8e2 | |||
212e5d1a72 | |||
713952b9c7 | |||
20b8fc075b | |||
fc77f0bb96 | |||
2eb7d0d88c | |||
41493b1e3f | |||
f526bb2ecb | |||
4e37e12c06 | |||
d83ab141f6 | |||
11236dd545 | |||
bf8a154bec | |||
2b9ecd6eec | |||
3712a70115 | |||
e4f01a6825 | |||
3549cbb3a2 | |||
7c17697cae | |||
0e1d306b2e | |||
70c208ead7 | |||
2d25662b81 | |||
e12edca29a | |||
7e0663e4e0 | |||
4bd736e1a7 | |||
d39830a4dc | |||
d7c9f947ed | |||
84426631b4 | |||
2c9c2e139e | |||
a540bae7a9 | |||
891b568678 | |||
901360b902 | |||
c8295e1485 | |||
9cc8ebd351 |
@ -52,7 +52,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -8,19 +8,26 @@ 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-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
|
||||
@ -33,8 +40,12 @@ afl-tmin.8
|
||||
afl-whatsup.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
as
|
||||
ld
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/unicornafl/
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
core\.*
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
|
16
.travis.yml
16
.travis.yml
@ -5,6 +5,7 @@ sudo: required
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
|
||||
matrix:
|
||||
include:
|
||||
@ -17,10 +18,10 @@ matrix:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env: NAME="trusty-amd64" MODERN="no" GCC="4.8"
|
||||
- os: linux
|
||||
dist: xenial
|
||||
arch: arm64
|
||||
env: NAME="xenial-arm64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0" AFL_NO_X86="1" CPU_TARGET="aarch64"
|
||||
# - os: linux # until travis can fix this!
|
||||
# dist: xenial
|
||||
# arch: arm64
|
||||
# env: NAME="xenial-arm64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0" AFL_NO_X86="1" CPU_TARGET="aarch64"
|
||||
# - os: osx
|
||||
# osx_image: xcode11.2
|
||||
# env: NAME="osx" HOMEBREW_NO_ANALYTICS="1" LINK="http://releases.llvm.org/9.0.0/" NAME="clang+llvm-9.0.0-x86_64-darwin-apple"
|
||||
@ -28,6 +29,7 @@ matrix:
|
||||
jobs:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- arch: arm64
|
||||
|
||||
env:
|
||||
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_STOP_MANUALLY=1
|
||||
@ -39,8 +41,8 @@ before_install:
|
||||
# export LLVM_DIR=${TRAVIS_BUILD_DIR}/${LLVM_PACKAGE}
|
||||
- echo Testing on $NAME
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then wget "$LINK""$NAME".tar.xz ; export LLVM_CONFIG=`pwd`/"$NAME" ; tar xJf "$NAME".tar.xz ; fi
|
||||
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y libtool libtool-bin automake bison libglib2.0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils ; fi
|
||||
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils ; fi
|
||||
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y libtool libtool-bin automake bison libglib2.0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev ; fi
|
||||
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils libcmocka-dev ; fi
|
||||
|
||||
script:
|
||||
- gcc -v
|
||||
@ -50,4 +52,4 @@ script:
|
||||
- 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
|
||||
- make tests
|
||||
- travis_terminate 0
|
||||
# - travis_terminate 0
|
||||
|
@ -3,17 +3,20 @@
|
||||
Each modified source file, before merging, must be formatted.
|
||||
|
||||
```
|
||||
make code-formatter
|
||||
make code-format
|
||||
```
|
||||
|
||||
This should be fine if you modified one of the files already present in the
|
||||
project, otherwise run:
|
||||
project, or added a file in a directory we already format, otherwise run:
|
||||
|
||||
```
|
||||
./.custom-format.py -i file-that-you-have-created.c
|
||||
```
|
||||
|
||||
Regarding the coding style, please follow the AFL style.
|
||||
No camel case at all and use the AFL's macros when possible (e.g. WARNF, FATAL, ...).
|
||||
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 general as possible.
|
||||
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.
|
||||
|
@ -31,7 +31,7 @@ ARG CC=gcc-9
|
||||
ARG CXX=g++-9
|
||||
ARG LLVM_CONFIG=llvm-config-9
|
||||
|
||||
RUN git clone https://github.com/vanhauser-thc/AFLplusplus
|
||||
RUN git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
|
||||
RUN cd AFLplusplus && make clean && make distrib && \
|
||||
make install && cd .. && rm -rf AFLplusplus
|
||||
|
482
GNUmakefile
Normal file
482
GNUmakefile
Normal file
@ -0,0 +1,482 @@
|
||||
#
|
||||
# american fuzzy lop++ - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2013, 2014, 2015, 2016, 2017 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
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
# the hash character is treated differently in different make versions
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
|
||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
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"
|
||||
CFLAGS_OPT = -march=native
|
||||
endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(shell uname -m)" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
ifneq "$(shell uname -m)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
override CFLAGS += -Wall -g -Wno-pointer-sign \
|
||||
-I include/ -Werror -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
ifneq "$(shell command -v python3m 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3m-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell command -v python3 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell command -v python 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python-config --includes)
|
||||
PYTHON_LIB ?= $(shell python-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
else
|
||||
BUILD_DATE ?= $(shell date "+%Y-%m-%d")
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
|
||||
CFLAGS += -static
|
||||
LDFLAGS += -lm -lpthread -lz -lutil
|
||||
endif
|
||||
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
ASAN_LDFLAGS+=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
$(info Compiling ASAN version of binaries)
|
||||
CFLAGS+=$(ASAN_CFLAGS)
|
||||
LDFLAGS+=$(ASAN_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifdef PROFILING
|
||||
$(info Compiling profiling version of binaries)
|
||||
CFLAGS+=-pg
|
||||
LDFLAGS+=-pg
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
|
||||
man: $(MANPAGES)
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
@rm -f test/errors
|
||||
|
||||
performance-tests: performance-test
|
||||
test-performance: performance-test
|
||||
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap, radamsa"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything. for qemu_mode it means it deletes all downloads as well"
|
||||
@echo "code-format: format the code, do this before you commit and send a PR please!"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "unit: perform unit tests (based on cmocka)"
|
||||
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
|
||||
@echo "help: shows these build options :-)"
|
||||
@echo "=========================================="
|
||||
@echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
|
||||
@echo
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev or python2-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
radamsa: src/third_party/libradamsa/libradamsa.so
|
||||
cp src/third_party/libradamsa/libradamsa.so .
|
||||
|
||||
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
||||
$(MAKE) -C src/third_party/libradamsa/ CFLAGS="$(CFLAGS)"
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
|
||||
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
|
||||
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
|
||||
$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_maybe_alloc
|
||||
|
||||
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
|
||||
unit_list: test/unittests/unit_list.o
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_list
|
||||
|
||||
test/unittests/preallocable.o : $(COMM_HDR) include/afl-prealloc.h test/unittests/preallocable.c $(AFL_FUZZ_FILES)
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CFLAGS_FLTO) -c test/unittests/preallocable.c -o test/unittests/preallocable.o
|
||||
|
||||
unit_preallocable: test/unittests/unit_preallocable.o
|
||||
$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_preallocable
|
||||
|
||||
unit_clean:
|
||||
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
|
||||
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean
|
||||
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i libdislocator/*.c
|
||||
./.custom-format.py -i libtokencap/*.c
|
||||
./.custom-format.py -i llvm_mode/*.c
|
||||
./.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/*.cc
|
||||
./.custom-format.py -i examples/*/*.c
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i qemu_mode/patches/*.h
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qbdi_mode/*.c
|
||||
./.custom-format.py -i qbdi_mode/*.cpp
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
all_done: test_build
|
||||
@if [ ! "`type clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.md for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.1.tar.xz afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/socket_fuzzing clean
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C src/third_party/libradamsa/ clean
|
||||
-rm -rf unicorn_mode/unicornafl
|
||||
|
||||
distrib: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
binary-only: all radamsa
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
source-only: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -hh 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
install: all $(MANPAGES)
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libradamsa.so ]; then set -e; install -m 755 libradamsa.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
|
||||
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
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
449
Makefile
449
Makefile
@ -1,447 +1,2 @@
|
||||
#
|
||||
# american fuzzy lop++ - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2013, 2014, 2015, 2016, 2017 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
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
# the hash character is treated differently in different make versions
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
|
||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_OPT = -march=native
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(shell uname -m)" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
ifneq "$(shell uname -m)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
override CFLAGS += -Wall -g -Wno-pointer-sign -I include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function -fcommon
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
ifneq "$(shell which python3m)" ""
|
||||
ifneq "$(shell which python3m-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3m-config --libs --embed)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3m-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell which python3)" ""
|
||||
ifneq "$(shell which python3-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3-config --libs --embed)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell which python)" ""
|
||||
ifneq "$(shell which python-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python-config --includes)
|
||||
PYTHON_LIB ?= $(shell python-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" -I 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" -I 2>/dev/null || date -u -I)
|
||||
else
|
||||
BUILD_DATE ?= $(shell date -I)
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
|
||||
CFLAGS += -static
|
||||
LDFLAGS += -lm -lrt -lpthread -lz -lutil
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
CFLAGS+=-fsanitize=address
|
||||
LDFLAGS+=-fsanitize=address
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
|
||||
man: $(MANPAGES)
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
@rm -f test/errors
|
||||
|
||||
performance-tests: performance-test
|
||||
test-performance: performance-test
|
||||
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap, radamsa"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything. for qemu_mode it means it deletes all downloads as well"
|
||||
@echo "code-format: format the code, do this before you commit and send a PR please!"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
|
||||
@echo "help: shows these build options :-)"
|
||||
@echo "=========================================="
|
||||
@echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
|
||||
@echo
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@which $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev or python2-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
radamsa: src/third_party/libradamsa/libradamsa.so
|
||||
cp src/third_party/libradamsa/libradamsa.so .
|
||||
|
||||
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
||||
$(MAKE) -C src/third_party/libradamsa/ CFLAGS="$(CFLAGS)"
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(AFL_FUZZ_FILES) -D_AFL_DOCUMENT_MUTATIONS src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(LDFLAGS) $(PYFLAGS)
|
||||
|
||||
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i libdislocator/*.c
|
||||
./.custom-format.py -i libtokencap/*.c
|
||||
./.custom-format.py -i llvm_mode/*.c
|
||||
./.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/*.cc
|
||||
./.custom-format.py -i examples/*/*.c
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i qemu_mode/patches/*.h
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qbdi_mode/*.c
|
||||
./.custom-format.py -i qbdi_mode/*.cpp
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
all_done: test_build
|
||||
@if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.1.tar.xz afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast *.so *.8
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/socket_fuzzing clean
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C src/third_party/libradamsa/ clean
|
||||
-rm -rf unicorn_mode/unicornafl
|
||||
|
||||
distrib: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
binary-only: all radamsa
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
source-only: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -h 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
install: all $(MANPAGES)
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
ifndef AFL_TRACE_PC
|
||||
if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
else
|
||||
if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
endif
|
||||
if [ -f afl-llvm-rt-32.o ]; then set -e; install -m 755 afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-llvm-rt-64.o ]; then set -e; install -m 755 afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f compare-transform-pass.so ]; then set -e; install -m 755 compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
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 libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libradamsa.so ]; then set -e; install -m 755 libradamsa.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
$(MAKE) -C examples/socket_fuzzing install
|
||||
$(MAKE) -C examples/argv_fuzzing install
|
||||
|
||||
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
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
||||
|
||||
all:
|
||||
@echo please use GNU make, thanks!
|
||||
|
165
README.md
165
README.md
@ -2,25 +2,27 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
||||

|
||||

|
||||
|
||||
Release Version: 2.61c
|
||||
Release Version: [2.63c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 2.61d
|
||||
Github Version: 2.63d
|
||||
|
||||
includes all necessary/interesting changes from Google's afl 2.56b
|
||||
|
||||
Originally developed by Michal "lcamtuf" Zalewski.
|
||||
|
||||
Repository: [https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
afl++ is maintained by Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
||||
Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
|
||||
afl++ is maintained by:
|
||||
* Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
||||
* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
* Andrea Fioraldi <andreafioraldi@gmail.com> and
|
||||
* Dominik Maier <mail@dmnk.co>.
|
||||
|
||||
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
|
||||
it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
|
||||
|
||||
|
||||
## The enhancements compared to the original stock afl
|
||||
|
||||
Many improvements were made over the official afl release - which did not
|
||||
@ -42,9 +44,9 @@
|
||||
|
||||
* Custom mutator by a library (instead of Python) by kyakdan
|
||||
|
||||
* unicorn_mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
||||
* Unicron mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
||||
|
||||
* laf-intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
|
||||
* LAF-Intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
|
||||
|
||||
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
||||
|
||||
@ -52,35 +54,47 @@
|
||||
|
||||
* Win32 PE binary-only fuzzing with QEMU and Wine
|
||||
|
||||
* Radamsa mutator (enable with `-R` to add or `-RR` to run it exclusivly).
|
||||
* Radamsa mutator (enable with `-R` to add or `-RR` to run it exclusively).
|
||||
|
||||
* qbdi_mode: fuzz android native libraries via QBDI framework
|
||||
* QBDI mode to fuzz android native libraries via QBDI framework
|
||||
|
||||
* The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
|
||||
|
||||
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
|
||||
|
||||
A more thorough list is available in the PATCHES file.
|
||||
|
||||
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
|
||||
| ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
|
||||
| NeverZero | x | x(1) | (2) | x | x |
|
||||
| Persistent mode | | x | x | x86[_64]/arm[64] | x |
|
||||
| laf-intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm |
|
||||
| LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm |
|
||||
| CmpLog | | x | | x86[_64]/arm[64] | |
|
||||
| Whitelist | | x | x | (x)(3) | |
|
||||
| Non-colliding coverage | | x(4) | | (x)(5) | |
|
||||
| InsTrim | | x | | | |
|
||||
| Ngram prev_loc coverage | | x(6) | | | |
|
||||
| Context coverage | | x | | | |
|
||||
| Snapshot LKM support | | x | | (x)(5) | |
|
||||
|
||||
neverZero:
|
||||
|
||||
(1) only in LLVM >= 9.0 due to a bug in llvm in previous versions
|
||||
(1) default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
|
||||
|
||||
(2) gcc creates non-performant code, hence it is disabled in gcc_plugin
|
||||
(2) GCC creates non-performant code, hence it is disabled in gcc_plugin
|
||||
|
||||
(3) partially via AFL_CODE_START/AFL_CODE_END
|
||||
|
||||
(4) Only for LLVM >= 9 and not all targets compile
|
||||
|
||||
(5) upcoming, development in the branch
|
||||
|
||||
(6) not compatible with LTO and InsTrim and needs at least LLVM >= 4.1
|
||||
|
||||
So all in all this is the best-of afl that is currently out there :-)
|
||||
|
||||
For new versions and additional information, check out:
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
To compare notes with other users or get notified about major new features,
|
||||
send a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
@ -88,13 +102,25 @@
|
||||
See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to
|
||||
read this file.
|
||||
|
||||
## Branches
|
||||
|
||||
The following branches exist:
|
||||
|
||||
* [master/trunk](https://github.com/AFLplusplus/AFLplusplus/) : stable state of afl++ - it is synced from dev from time to
|
||||
time when we are satisfied with it's stability
|
||||
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
|
||||
checkout which does not compile or has a bug. *We only accept PRs in dev!!*
|
||||
* (any other) : experimental branches to work on specific features or testing
|
||||
new functionality or changes.
|
||||
|
||||
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
|
||||
|
||||
## Google Summer of Code 2020 (and any other students and enthusiast developers)
|
||||
|
||||
We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
|
||||
|
||||
We have several ideas we would like to see in AFL++ to make it even better.
|
||||
However we already work on so many things that we do not have the time for
|
||||
However, we already work on so many things that we do not have the time for
|
||||
all the big ideas.
|
||||
|
||||
This can be your way to support and contribute to AFL++ - extend it to
|
||||
@ -102,13 +128,16 @@ something cool
|
||||
|
||||
We have an idea list in [docs/ideas.md](docs/ideas.md)
|
||||
|
||||
## 0) Building and installing afl++
|
||||
For everyone who wants to contribute (and send pull requests) please read
|
||||
[CONTRIBUTING.md](CONTRIBUTING.md) before your submit.
|
||||
|
||||
## Building and installing afl++
|
||||
|
||||
afl++ has many build options.
|
||||
The easiest is to build and install everything:
|
||||
|
||||
```shell
|
||||
$ sudo apt install build-essential libtool-bin python3 automake bison libglib2.0-dev libpixman-1-dev clang
|
||||
$ sudo apt install build-essential libtool-bin python3 automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools
|
||||
$ make distrib
|
||||
$ sudo make install
|
||||
```
|
||||
@ -133,6 +162,7 @@ These build targets exist:
|
||||
* clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well
|
||||
* code-format: format the code, do this before you commit and send a PR please!
|
||||
* tests: runs test cases to ensure that all features are still working as they should
|
||||
* unit: perform unit tests (based on cmocka)
|
||||
* help: shows these build options
|
||||
|
||||
[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html) you can also build statically linked versions of the
|
||||
@ -146,7 +176,9 @@ These build options exist:
|
||||
|
||||
* STATIC - compile AFL++ static
|
||||
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
* PROFILING - compile with profiling information (gprof)
|
||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
|
||||
|
||||
e.g.: make ASAN_BUILD=1
|
||||
|
||||
@ -156,11 +188,12 @@ Hence gcc-9 and especially llvm-9 should be the compilers of choice.
|
||||
If your distribution does not have them, you can use the Dockerfile:
|
||||
|
||||
```shell
|
||||
$ docker build -t aflplusplus
|
||||
$ cd AFLplusplus
|
||||
$ sudo docker build -t aflplusplus .
|
||||
```
|
||||
|
||||
|
||||
## 1) Challenges of guided fuzzing
|
||||
## Challenges of guided fuzzing
|
||||
|
||||
Fuzzing is one of the most powerful and proven strategies for identifying
|
||||
security issues in real-world software; it is responsible for the vast
|
||||
@ -175,9 +208,9 @@ There have been numerous attempts to solve this problem. One of the early
|
||||
approaches - pioneered by Tavis Ormandy - is corpus distillation. The method
|
||||
relies on coverage signals to select a subset of interesting seeds from a
|
||||
massive, high-quality corpus of candidate files, and then fuzz them by
|
||||
traditional means. The approach works exceptionally well, but requires such
|
||||
traditional means. The approach works exceptionally well but requires such
|
||||
a corpus to be readily available. In addition, block coverage measurements
|
||||
provide only a very simplistic understanding of program state, and are less
|
||||
provide only a very simplistic understanding of the program state and are less
|
||||
useful for guiding the fuzzing effort in the long haul.
|
||||
|
||||
Other, more sophisticated research has focused on techniques such as program
|
||||
@ -187,7 +220,7 @@ to suffer from reliability and performance problems in practical uses - and
|
||||
currently do not offer a viable alternative to "dumb" fuzzing techniques.
|
||||
|
||||
|
||||
## 2) The afl-fuzz approach
|
||||
## The afl-fuzz approach
|
||||
|
||||
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
|
||||
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
|
||||
@ -198,7 +231,7 @@ Simplifying a bit, the overall algorithm can be summed up as:
|
||||
|
||||
1) Load user-supplied initial test cases into the queue,
|
||||
|
||||
2) Take next input file from the queue,
|
||||
2) Take the next input file from the queue,
|
||||
|
||||
3) Attempt to trim the test case to the smallest size that doesn't alter
|
||||
the measured behavior of the program,
|
||||
@ -226,10 +259,10 @@ The fuzzer is thoroughly tested to deliver out-of-the-box performance far
|
||||
superior to blind fuzzing or coverage-only tools.
|
||||
|
||||
|
||||
## 3) Instrumenting programs for use with AFL
|
||||
## Instrumenting programs for use with AFL
|
||||
|
||||
PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
|
||||
instead of afl-gcc/afl-g++ is much faster and has a few cool features.
|
||||
instead of afl-gcc/afl-g++ is much faster and has many cool features.
|
||||
See llvm_mode/ - however few code does not compile with llvm.
|
||||
We support llvm versions 3.8.0 to 11.
|
||||
|
||||
@ -265,7 +298,7 @@ Using partial instrumentation is also recommended, see
|
||||
When testing libraries, you need to find or write a simple program that reads
|
||||
data from stdin or from a file and passes it to the tested library. In such a
|
||||
case, it is essential to link this executable against a static version of the
|
||||
instrumented library, or to make sure that the correct .so file is loaded at
|
||||
instrumented library or to make sure that the correct .so file is loaded at
|
||||
runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static
|
||||
build, usually possible via:
|
||||
|
||||
@ -282,7 +315,7 @@ PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asa
|
||||
file for important caveats.
|
||||
|
||||
|
||||
## 4) Instrumenting binary-only apps
|
||||
## Instrumenting binary-only apps
|
||||
|
||||
When source code is *NOT* available, the fuzzer offers experimental support for
|
||||
fast, on-the-fly instrumentation of black-box binaries. This is accomplished
|
||||
@ -298,7 +331,7 @@ $ ./build_qemu_support.sh
|
||||
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
||||
|
||||
If possible you should use the persistent mode, see [README.persistent.md](README.persistent.md).
|
||||
If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
|
||||
|
||||
The mode is approximately 2-5x slower than compile-time instrumentation, is
|
||||
less conducive to parallelization, and may have some other quirks.
|
||||
@ -310,18 +343,22 @@ the speed compared to qemu_mode.
|
||||
A more comprehensive description of these and other options can be found in
|
||||
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
|
||||
|
||||
## Good examples and writeups
|
||||
|
||||
## 5) Good examples and writeups
|
||||
|
||||
Here are some good writeups to show how to effectibly use AFL++:
|
||||
Here are some good writeups to show how to effectively use AFL++:
|
||||
|
||||
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
|
||||
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
|
||||
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
|
||||
|
||||
If you are interested in fuzzing structured data (where you define what the
|
||||
structure is), these two links have you covered:
|
||||
* [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
||||
* [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
||||
|
||||
If you find other good ones, please send them to us :-)
|
||||
|
||||
## 6) Power schedules
|
||||
## Power schedules
|
||||
|
||||
The power schedules were copied from Marcel Böhme's excellent AFLfast
|
||||
implementation and expand on the ability to discover new paths and
|
||||
@ -335,21 +372,24 @@ The available schedules are:
|
||||
- quad
|
||||
- lin
|
||||
- exploit
|
||||
- mmopt (experimental)
|
||||
- rare (experimental)
|
||||
|
||||
In parallel mode (-M/-S, several instances with shared queue), we suggest to
|
||||
run the master using the exploit schedule (-p exploit) and the slaves with a
|
||||
combination of cut-off-exponential (-p coe), exponential (-p fast; default),
|
||||
and explore (-p explore) schedules.
|
||||
In parallel mode (-M/-S, several instances with the shared queue), we suggest to
|
||||
run the master using the explore or fast schedule (-p explore) and the slaves
|
||||
with a combination of cut-off-exponential (-p coe), exponential (-p fast),
|
||||
explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does
|
||||
not perform well for a target, restart the slave with a different schedule.
|
||||
|
||||
In single mode, using -p fast is usually more beneficial than the default
|
||||
explore mode.
|
||||
(We don't want to change the default behaviour of afl, so "fast" has not been
|
||||
In single mode, using -p fast is usually slightly more beneficial than the
|
||||
default explore mode.
|
||||
(We don't want to change the default behavior of afl, so "fast" has not been
|
||||
made the default mode).
|
||||
|
||||
More details can be found in the paper published at the 23rd ACM Conference on
|
||||
Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
|
||||
|
||||
## 7) Choosing initial test cases
|
||||
## Choosing initial test cases
|
||||
|
||||
To operate correctly, the fuzzer requires one or more starting file that
|
||||
contains a good example of the input data normally expected by the targeted
|
||||
@ -370,7 +410,7 @@ the afl-cmin utility to identify a subset of functionally distinct files that
|
||||
exercise different code paths in the target binary.
|
||||
|
||||
|
||||
## 8) Fuzzing binaries
|
||||
## Fuzzing binaries
|
||||
|
||||
The fuzzing process itself is carried out by the afl-fuzz utility. This program
|
||||
requires a read-only directory with initial test cases, a separate place to
|
||||
@ -407,18 +447,18 @@ steps, which can take several days, but tend to produce neat test cases. If you
|
||||
want quick & dirty results right away - akin to zzuf and other traditional
|
||||
fuzzers - add the -d option to the command line.
|
||||
|
||||
## 9) Interpreting output
|
||||
## Interpreting output
|
||||
|
||||
See the [docs/status_screen.md](docs/status_screen.md) file for information on
|
||||
how to interpret the displayed stats and monitor the health of the process. Be
|
||||
sure to consult this file especially if any UI elements are highlighted in red.
|
||||
|
||||
The fuzzing process will continue until you press Ctrl-C. At minimum, you want
|
||||
The fuzzing process will continue until you press Ctrl-C. At a minimum, you want
|
||||
to allow the fuzzer to complete one queue cycle, which may take anywhere from a
|
||||
couple of hours to a week or so.
|
||||
|
||||
There are three subdirectories created within the output directory and updated
|
||||
in real time:
|
||||
in real-time:
|
||||
|
||||
- queue/ - test cases for every distinctive execution path, plus all the
|
||||
starting files given by the user. This is the synthesized corpus
|
||||
@ -443,7 +483,7 @@ involve any state transitions not seen in previously-recorded faults. If a
|
||||
single bug can be reached in multiple ways, there will be some count inflation
|
||||
early in the process, but this should quickly taper off.
|
||||
|
||||
The file names for crashes and hangs are correlated with parent, non-faulting
|
||||
The file names for crashes and hangs are correlated with the parent, non-faulting
|
||||
queue entries. This should help with debugging.
|
||||
|
||||
When you can't reproduce a crash found by afl-fuzz, the most likely cause is
|
||||
@ -467,7 +507,7 @@ If you have gnuplot installed, you can also generate some pretty graphs for any
|
||||
active fuzzing task using afl-plot. For an example of how this looks like,
|
||||
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
|
||||
|
||||
## 10) Parallelized fuzzing
|
||||
## Parallelized fuzzing
|
||||
|
||||
Every instance of afl-fuzz takes up roughly one core. This means that on
|
||||
multi-core systems, parallelization is necessary to fully utilize the hardware.
|
||||
@ -478,7 +518,7 @@ The parallel fuzzing mode also offers a simple way for interfacing AFL to other
|
||||
fuzzers, to symbolic or concolic execution engines, and so forth; again, see the
|
||||
last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips.
|
||||
|
||||
## 12) Fuzzer dictionaries
|
||||
## Fuzzer dictionaries
|
||||
|
||||
By default, afl-fuzz mutation engine is optimized for compact data formats -
|
||||
say, images, multimedia, compressed data, regular expression syntax, or shell
|
||||
@ -507,13 +547,13 @@ instrumentation feedback alone. This actually works in practice, say:
|
||||
PS. Even when no explicit dictionary is given, afl-fuzz will try to extract
|
||||
existing syntax tokens in the input corpus by watching the instrumentation
|
||||
very closely during deterministic byte flips. This works for some types of
|
||||
parsers and grammars, but isn't nearly as good as the -x mode.
|
||||
parsers and grammars but isn't nearly as good as the -x mode.
|
||||
|
||||
If a dictionary is really hard to come by, another option is to let AFL run
|
||||
for a while, and then use the token capture library that comes as a companion
|
||||
for a while and then use the token capture library that comes as a companion
|
||||
utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md).
|
||||
|
||||
## 13) Crash triage
|
||||
## Crash triage
|
||||
|
||||
The coverage-based grouping of crashes usually produces a small data set that
|
||||
can be quickly triaged manually or with a very simple GDB or Valgrind script.
|
||||
@ -525,7 +565,7 @@ difficult to quickly evaluate for exploitability without a lot of debugging and
|
||||
code analysis work. To assist with this task, afl-fuzz supports a very unique
|
||||
"crash exploration" mode enabled with the -C flag.
|
||||
|
||||
In this mode, the fuzzer takes one or more crashing test cases as the input,
|
||||
In this mode, the fuzzer takes one or more crashing test cases as the input
|
||||
and uses its feedback-driven fuzzing strategies to very quickly enumerate all
|
||||
code paths that can be reached in the program while keeping it in the
|
||||
crashing state.
|
||||
@ -560,12 +600,11 @@ be critical, and which are not; while not bulletproof, it can often offer quick
|
||||
insights into complex file formats. More info about its operation can be found
|
||||
near the end of [docs/technical_details.md](docs/technical_details.md).
|
||||
|
||||
|
||||
## 14) Going beyond crashes
|
||||
## Going beyond crashes
|
||||
|
||||
Fuzzing is a wonderful and underutilized technique for discovering non-crashing
|
||||
design and implementation errors, too. Quite a few interesting bugs have been
|
||||
found by modifying the target programs to call abort() when, say:
|
||||
found by modifying the target programs to call abort() when say:
|
||||
|
||||
- Two bignum libraries produce different outputs when given the same
|
||||
fuzzer-generated input,
|
||||
@ -584,10 +623,10 @@ if you are the maintainer of a particular package, you can make this code
|
||||
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
|
||||
shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).
|
||||
|
||||
## 15) Common-sense risks
|
||||
## Common-sense risks
|
||||
|
||||
Please keep in mind that, similarly to many other computationally-intensive
|
||||
tasks, fuzzing may put strain on your hardware and on the OS. In particular:
|
||||
tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
|
||||
|
||||
- Your CPU will run hot and will need adequate cooling. In most cases, if
|
||||
cooling is insufficient or stops working properly, CPU speeds will be
|
||||
@ -613,14 +652,14 @@ tasks, fuzzing may put strain on your hardware and on the OS. In particular:
|
||||
$ iostat -d 3 -x -k [...optional disk ID...]
|
||||
```
|
||||
|
||||
## 16) Known limitations & areas for improvement
|
||||
## Known limitations & areas for improvement
|
||||
|
||||
Here are some of the most important caveats for AFL:
|
||||
|
||||
- AFL detects faults by checking for the first spawned process dying due to
|
||||
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
|
||||
these signals may need to have the relevant code commented out. In the same
|
||||
vein, faults in child processed spawned by the fuzzed target may evade
|
||||
vein, faults in child processes spawned by the fuzzed target may evade
|
||||
detection unless you manually add some code to catch that.
|
||||
|
||||
- As with any other brute-force tool, the fuzzer offers limited coverage if
|
||||
@ -653,7 +692,7 @@ Here are some of the most important caveats for AFL:
|
||||
|
||||
Beyond this, see INSTALL for platform-specific tips.
|
||||
|
||||
## 17) Special thanks
|
||||
## Special thanks
|
||||
|
||||
Many of the improvements to the original afl and afl++ wouldn't be possible
|
||||
without feedback, bug reports, or patches from:
|
||||
@ -701,16 +740,16 @@ without feedback, bug reports, or patches from:
|
||||
Nathan Voss Dominik Maier
|
||||
Andrea Biondo Vincent Le Garrec
|
||||
Khaled Yakdan Kuang-che Wu
|
||||
Josephine Calliotte
|
||||
Josephine Calliotte Konrad Welc
|
||||
```
|
||||
|
||||
Thank you!
|
||||
(For people sending pull requests - please add yourself to this list :-)
|
||||
|
||||
## 18) Contact
|
||||
## Contact
|
||||
|
||||
Questions? Concerns? Bug reports? The contributors can be reached via
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
There is also a mailing list for the afl project; to join, send a mail to
|
||||
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse
|
||||
|
88
TODO.md
88
TODO.md
@ -1,92 +1,48 @@
|
||||
# TODO list for AFL++
|
||||
|
||||
## Roadmap 2.61
|
||||
## Roadmap 2.63
|
||||
|
||||
Makefile:
|
||||
- -march=native -Ofast -flto=full (especially for afl-fuzz)
|
||||
- complete custom_mutator API changes and documentation
|
||||
- fix stability calculation bug
|
||||
|
||||
llvm_mode:
|
||||
- using lto + opt to instrument at link time, and using a sat solver to
|
||||
select basic block IDs that do not result in collisions
|
||||
(Solution for "The far away future", see bottom of file)
|
||||
|
||||
qemu_mode:
|
||||
- ensure redqueen implementation works fine
|
||||
- ensure no issues in persistent mode
|
||||
## Roadmap 2.64
|
||||
|
||||
- context sensitive branch coverage in llvm_mode
|
||||
- random crc32 HASH_CONST per run? because with 65536 paths we have collisions
|
||||
- namespace for targets? e.g. network
|
||||
- libradamsa as a custom module?
|
||||
- laf-intel build auto-dictionary?
|
||||
|
||||
## Further down the road
|
||||
|
||||
afl-fuzz:
|
||||
- sync_fuzzers(): only masters sync from all, slaves only sync from master
|
||||
(@andrea: be careful, often people run all slaves)
|
||||
- ascii_only mode
|
||||
- ascii_only mode for mutation output
|
||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||
|
||||
llvm_mode:
|
||||
- added context sensitive branch coverage
|
||||
- add CT cov and ngram cov to LTO and InsTrim
|
||||
- better whitelist solution for LTO
|
||||
|
||||
gcc_plugin:
|
||||
- laf-intel
|
||||
- better instrumentation
|
||||
- better instrumentation (seems to be better with gcc-9+)
|
||||
|
||||
qemu_mode:
|
||||
- update to 4.x (probably this will be skipped :( )
|
||||
- non colliding instrumentation
|
||||
- instrim for QEMU mode via static analysis (with r2pipe? or angr?)
|
||||
Idea: The static analyzer outputs a map in which each edge that must be
|
||||
skipped is marked with 1. QEMU loads it at startup in the parent process.
|
||||
- rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END, AFL_COMPCOV_LEVEL?)
|
||||
- add AFL_QEMU_EXITPOINT (maybe multiple?)
|
||||
- rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END,
|
||||
AFL_COMPCOV_LEVEL?)
|
||||
- add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as we have
|
||||
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
|
||||
|
||||
custom_mutators:
|
||||
- rip what Superion is doing into custom mutators for js, php, etc.
|
||||
- uniform python and custom mutators API
|
||||
|
||||
|
||||
## The far away future:
|
||||
|
||||
Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges.
|
||||
At afl's default map that means ~16 collisions and ~3 wrappings.
|
||||
|
||||
- Solution #1: increase map size.
|
||||
|
||||
=> speed loss is bad. last resort solution
|
||||
|
||||
every +1 decreases fuzzing speed by ~10% and halfs the collisions
|
||||
birthday paradox predicts collisions at this # of edges:
|
||||
|
||||
| mapsize | collisions |
|
||||
| :-----: | :--------: |
|
||||
| 2^16 | 302 |
|
||||
| 2^17 | 427 |
|
||||
| 2^18 | 603 |
|
||||
| 2^19 | 853 |
|
||||
| 2^20 | 1207 |
|
||||
| 2^21 | 1706 |
|
||||
| 2^22 | 2412 |
|
||||
| 2^23 | 3411 |
|
||||
| 2^24 | 4823 |
|
||||
|
||||
Increasing the map is an easy solution but also not a good one.
|
||||
|
||||
- Solution #2: use dynamic map size and collision free basic block IDs
|
||||
|
||||
=> This works and is the selected solution
|
||||
|
||||
This only works in llvm_mode and llvm >= 9 though
|
||||
A potential good future solution. Heiko/hexcoder follows this up
|
||||
|
||||
- Solution #3: write instruction pointers to a big shared map
|
||||
|
||||
=> Tested and it is a dead end
|
||||
|
||||
512kb/1MB shared map and the instrumented code writes the instruction
|
||||
pointer into the map. Map must be big enough but could be command line
|
||||
controlled.
|
||||
|
||||
Good: complete coverage information, nothing is lost. choice of analysis
|
||||
impacts speed, but this can be decided by user options
|
||||
|
||||
Neutral: a little bit slower but no loss of coverage
|
||||
|
||||
Bad: completely changes how afl uses the map and the scheduling.
|
||||
Overall another very good solution, Marc Heuse/vanHauser follows this up
|
||||
|
||||
|
31
afl-cmin
31
afl-cmin
@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
export AFL_QUIET=1
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
THISPATH=`dirname ${0}`
|
||||
export PATH="${THISPATH}:$PATH"
|
||||
awk -f - -- ${@+"$@"} <<'EOF'
|
||||
@ -23,7 +25,7 @@ awk -f - -- ${@+"$@"} <<'EOF'
|
||||
# ln
|
||||
# cp
|
||||
# pwd
|
||||
# which
|
||||
# type
|
||||
# cd
|
||||
# find
|
||||
# stat
|
||||
@ -94,15 +96,13 @@ function getopt(argc, argv, options, thisopt, i)
|
||||
|
||||
function usage() {
|
||||
print \
|
||||
"Usage: afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
|
||||
"afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
|
||||
"\n" \
|
||||
"Required parameters:\n" \
|
||||
"\n" \
|
||||
" -i dir - input directory with starting corpus\n" \
|
||||
" -o dir - output directory for minimized files\n" \
|
||||
"\n" \
|
||||
"Execution control settings:\n" \
|
||||
"\n" \
|
||||
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||
" -t msec - run time limit for child process (none)\n" \
|
||||
@ -116,11 +116,10 @@ function usage() {
|
||||
"For additional tips, please consult docs/README.md\n" \
|
||||
"\n" \
|
||||
"Environment variables used:\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
"AFL_PATH: path for the afl-showmap binary\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n" \
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
|
||||
> "/dev/stderr"
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -265,7 +264,7 @@ BEGIN {
|
||||
|
||||
if (target_bin && !exists_and_is_executable(target_bin)) {
|
||||
|
||||
"which "target_bin" 2>/dev/null" | getline tnew
|
||||
"command -v "target_bin" 2>/dev/null" | getline tnew
|
||||
if (!tnew || !exists_and_is_executable(tnew)) {
|
||||
print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
|
||||
exit 1
|
||||
@ -314,7 +313,7 @@ BEGIN {
|
||||
if (0 == system("test -f afl-cmin")) {
|
||||
showmap = "./afl-showmap"
|
||||
} else {
|
||||
"which afl-showmap 2>/dev/null" | getline showmap
|
||||
"command -v afl-showmap 2>/dev/null" | getline showmap
|
||||
}
|
||||
} else {
|
||||
showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
|
||||
@ -399,10 +398,20 @@ BEGIN {
|
||||
cur = 0;
|
||||
if (!stdin_file) {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
retval = system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
} else {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
retval = system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval) {
|
||||
print "[!]Exit code != 0 received from afl-showmap, terminating..."
|
||||
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
system("rmdir "out_dir)
|
||||
}
|
||||
exit retval
|
||||
}
|
||||
|
||||
#######################################################
|
||||
|
@ -51,6 +51,8 @@ TIMEOUT=none
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
|
||||
|
||||
export AFL_QUIET=1
|
||||
|
||||
while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
|
||||
case "$opt" in
|
||||
@ -126,7 +128,7 @@ Minimization settings:
|
||||
-C - keep crashing inputs, reject everything else
|
||||
-e - solve for edge coverage only, ignore hit counts
|
||||
|
||||
For additional tips, please consult docs/README.
|
||||
For additional tips, please consult docs/README.md.
|
||||
|
||||
Environment variables used:
|
||||
AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
|
||||
|
4
afl-plot
4
afl-plot
@ -32,6 +32,8 @@ an empty directory where this tool can write the resulting plots to.
|
||||
The program will put index.html and three PNG images in the output directory;
|
||||
you should be able to view it with any web browser of your choice.
|
||||
|
||||
Environment variables used:
|
||||
AFL_ALLOW_TMP: allow /var/tmp or /tmp for input and output directories
|
||||
_EOF_
|
||||
|
||||
exit 1
|
||||
@ -66,7 +68,7 @@ BANNER="`cat "$1/fuzzer_stats" | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
|
||||
|
||||
test "$BANNER" = "" && BANNER="(none)"
|
||||
|
||||
GNUPLOT=`which gnuplot 2>/dev/null`
|
||||
GNUPLOT=`command -v gnuplot 2>/dev/null`
|
||||
|
||||
if [ "$GNUPLOT" = "" ]; then
|
||||
|
||||
|
115
afl-whatsup
115
afl-whatsup
@ -18,12 +18,13 @@
|
||||
# instances of afl-fuzz.
|
||||
#
|
||||
|
||||
echo "status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
test "$1" = "-h" && {
|
||||
echo $0
|
||||
echo $0 [-s] output_directory
|
||||
echo
|
||||
echo afl-whatsup has no command line options
|
||||
echo Options:
|
||||
echo -s - skip details and output summary results only
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
@ -60,6 +61,13 @@ if [ -d queue ]; then
|
||||
|
||||
fi
|
||||
|
||||
RED=`tput setaf 9 1 1`
|
||||
GREEN=`tput setaf 2 1 1`
|
||||
BLUE=`tput setaf 4 1 1`
|
||||
YELLOW=`tput setaf 11 1 1`
|
||||
NC=`tput sgr0`
|
||||
RESET="$NC"
|
||||
|
||||
CUR_TIME=`date +%s`
|
||||
|
||||
TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1
|
||||
@ -74,6 +82,12 @@ TOTAL_CRASHES=0
|
||||
TOTAL_PFAV=0
|
||||
TOTAL_PENDING=0
|
||||
|
||||
# Time since last path / crash / hang, formatted as string
|
||||
FMT_TIME="0 days 0 hours"
|
||||
FMT_PATH="${RED}none seen yet${NC}"
|
||||
FMT_CRASH="none seen yet"
|
||||
FMT_HANG="none seen yet"
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
echo "Individual fuzzers"
|
||||
@ -82,6 +96,34 @@ if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
fi
|
||||
|
||||
fmt_duration()
|
||||
{
|
||||
DUR_STRING=
|
||||
if [ $1 -eq 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local duration=$((CUR_TIME - $1))
|
||||
local days=$((duration / 60 / 60 / 24))
|
||||
local hours=$(((duration / 60 / 60) % 24))
|
||||
local minutes=$(((duration / 60) % 60))
|
||||
local seconds=$((duration % 60))
|
||||
|
||||
if [ $days -gt 0 ]; then
|
||||
DUR_STRING="$days days, $hours hours"
|
||||
elif [ $hours -gt 0 ]; then
|
||||
DUR_STRING="$hours hours, $minutes minutes"
|
||||
elif [ $minutes -gt 0 ]; then
|
||||
DUR_STRING="$minutes minutes, $seconds seconds"
|
||||
else
|
||||
DUR_STRING="$seconds seconds"
|
||||
fi
|
||||
}
|
||||
|
||||
FIRST=true
|
||||
TOTAL_WCOP=
|
||||
TOTAL_LAST_PATH=0
|
||||
|
||||
for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
|
||||
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
|
||||
@ -91,9 +133,15 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
|
||||
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
|
||||
|
||||
test -n "$cycles_wo_finds" && {
|
||||
test -z "$FIRST" && TOTAL_WCOP="${TOTAL_WCOP}/"
|
||||
TOTAL_WCOP="${TOTAL_WCOP}${cycles_wo_finds}"
|
||||
FIRST=
|
||||
}
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) <<<"
|
||||
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
|
||||
echo
|
||||
|
||||
fi
|
||||
@ -124,8 +172,41 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
|
||||
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
|
||||
|
||||
if [ "$last_path" -gt "$TOTAL_LAST_PATH" ]; then
|
||||
TOTAL_LAST_PATH=$last_path
|
||||
fi
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
# Warnings in red
|
||||
TIMEOUT_PERC=$((exec_timeout * 100 / execs_done))
|
||||
if [ $TIMEOUT_PERC -ge 10 ]; then
|
||||
echo " ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
|
||||
fi
|
||||
|
||||
if [ $EXEC_SEC -lt 100 ]; then
|
||||
echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
|
||||
fi
|
||||
|
||||
fmt_duration $last_path && FMT_PATH=$DUR_STRING
|
||||
fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
|
||||
fmt_duration $last_hang && FMT_HANG=$DUR_STRING
|
||||
FMT_CWOP="not available"
|
||||
test -n "$cycles_wo_finds" && {
|
||||
test "$cycles_wo_finds" = 0 && FMT_CWOP="$cycles_wo_finds"
|
||||
test "$cycles_wo_finds" -gt 10 && FMT_CWOP="${YELLOW}$cycles_wo_finds${NC}"
|
||||
test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
|
||||
}
|
||||
|
||||
echo " last_path : $FMT_PATH"
|
||||
echo " last_crash : $FMT_CRASH"
|
||||
echo " last_hang : $FMT_HANG"
|
||||
echo " cycles_wo_finds : $FMT_CWOP"
|
||||
|
||||
CPU_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $3}')
|
||||
MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
|
||||
|
||||
echo " cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
|
||||
echo " cycle $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, path $cur_path/$paths_total (${PATH_PERC}%)"
|
||||
|
||||
if [ "$unique_crashes" = "0" ]; then
|
||||
@ -140,11 +221,28 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
|
||||
done
|
||||
|
||||
# Formatting for total time, time since last path, crash, and hang
|
||||
fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
|
||||
# Formatting for total execution
|
||||
FMT_EXECS="0 millions"
|
||||
EXECS_MILLION=$((TOTAL_EXECS / 1000 / 1000))
|
||||
EXECS_THOUSAND=$((TOTAL_EXECS / 1000 % 1000))
|
||||
if [ $EXECS_MILLION -gt 9 ]; then
|
||||
FMT_EXECS="$EXECS_MILLION millions"
|
||||
elif [ $EXECS_MILLION -gt 0 ]; then
|
||||
FMT_EXECS="$EXECS_MILLION millions, $EXECS_THOUSAND thousands"
|
||||
else
|
||||
FMT_EXECS="$EXECS_THOUSAND thousands"
|
||||
fi
|
||||
|
||||
rm -f "$TMP"
|
||||
|
||||
TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
|
||||
TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
|
||||
|
||||
test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
|
||||
fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
|
||||
|
||||
test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
|
||||
|
||||
echo "Summary stats"
|
||||
@ -156,9 +254,12 @@ if [ ! "$DEAD_CNT" = "0" ]; then
|
||||
echo " Dead or remote : $DEAD_CNT (excluded from stats)"
|
||||
fi
|
||||
|
||||
echo " Total run time : $TOTAL_DAYS days, $TOTAL_HRS hours"
|
||||
echo " Total execs : $((TOTAL_EXECS / 1000 / 1000)) million"
|
||||
echo " Total run time : $FMT_TIME"
|
||||
echo " Total execs : $FMT_EXECS"
|
||||
echo " Cumulative speed : $TOTAL_EPS execs/sec"
|
||||
if [ "$ALIVE_CNT" -gt "0" ]; then
|
||||
echo " Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
|
||||
fi
|
||||
echo " Pending paths : $TOTAL_PFAV faves, $TOTAL_PENDING total"
|
||||
|
||||
if [ "$ALIVE_CNT" -gt "1" ]; then
|
||||
@ -166,6 +267,8 @@ if [ "$ALIVE_CNT" -gt "1" ]; then
|
||||
fi
|
||||
|
||||
echo " Crashes found : $TOTAL_CRASHES locally unique"
|
||||
echo "Cycles without finds : $TOTAL_WCOP"
|
||||
echo " Time without finds : $TOTAL_LAST_PATH"
|
||||
echo
|
||||
|
||||
exit 0
|
||||
|
@ -238,362 +238,6 @@
|
||||
"\\p{Nd}"
|
||||
"\\P{Any}"
|
||||
"\\p{Changes_When_NFKC_Casefolded}"
|
||||
"L~"
|
||||
"P{scx=Greek}??"
|
||||
"Q~"
|
||||
"R??"
|
||||
"R!??oo(E=?ar)baz-"
|
||||
"Sc?Sc{?{?"
|
||||
"U~"
|
||||
"V~"
|
||||
"W~"
|
||||
"Xdtc"
|
||||
"X~"
|
||||
"X?"
|
||||
"[-123],}"
|
||||
"[-????]+,}"
|
||||
"[00011],}"
|
||||
"[011],}"
|
||||
"[0],}"
|
||||
"[1111],}"
|
||||
"[111],}"
|
||||
"[118],}"
|
||||
"[11],}"
|
||||
"[11a],}"
|
||||
"[[]{}()%^# ],}"
|
||||
"[]"
|
||||
"[],}"
|
||||
"[]{}()%^# ,}"
|
||||
"[^123],}"
|
||||
"[a-b-c],}"
|
||||
"[a-zA-Z0-9],}"
|
||||
"[b"
|
||||
"[bfoo(?!bar)baz"
|
||||
"[c!],}"
|
||||
"[c1],}"
|
||||
"[cA],}"
|
||||
"[cZ],}"
|
||||
"[c_],}"
|
||||
"[ca],}"
|
||||
"[cz],}"
|
||||
"[c~],}"
|
||||
"[c~]w"
|
||||
"[d-d],}"
|
||||
"[d-z],}"
|
||||
"[u???[11<([c?]?:u??<a>)dccc]"
|
||||
"[ud808udf45-ud809udccc],}"
|
||||
"[x"
|
||||
"[x],}"
|
||||
"[xdz],}"
|
||||
"[xyz],}"
|
||||
"[x?"
|
||||
"[x?n4n4"
|
||||
"[x??19?"
|
||||
"[z-d],}"
|
||||
"[~?"
|
||||
"[?????"
|
||||
"[?"
|
||||
"[???],}"
|
||||
"[????-????],}"
|
||||
"[????"
|
||||
"]"
|
||||
"],}"
|
||||
"]QrC[w~]Qr"
|
||||
"]}"
|
||||
"]~"
|
||||
"^?000???????????????????????????x60?"
|
||||
"^12(a(?:1(b12))2)1dyb?9"
|
||||
"^xi!q"
|
||||
"^xxx$,}"
|
||||
"abc"
|
||||
"abc60,0}?{?"
|
||||
"aic"
|
||||
"b~"
|
||||
"c"
|
||||
"c!,}"
|
||||
"c,}"
|
||||
"cA,}"
|
||||
"c_,}"
|
||||
"cjcJcicIckcK,}"
|
||||
"c~"
|
||||
"c~,}"
|
||||
"d"
|
||||
"d?"
|
||||
"d??"
|
||||
"d(?:ab[]?9}"
|
||||
"dpN?(?<a>.)?"
|
||||
"duu{123a?"
|
||||
"d{1,9"
|
||||
"d~"
|
||||
"e"
|
||||
"e~"
|
||||
"e?}"
|
||||
"f~"
|
||||
"g~"
|
||||
"h~"
|
||||
"i~"
|
||||
"j~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xx?~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxb~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxc~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxd~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxe~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxf~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxg~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxh~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxi~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxj~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxk~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxl~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxm~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxn~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxo~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxp~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxq~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxr~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxs~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxt~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxu~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxv~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxw~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxx~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxy~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxz~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xx?~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxn~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxo~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxp~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxq~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxr~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxs~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxt~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxu~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxv~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxw~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxx~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxy~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@??@a(P=b@??s@xxz~"
|
||||
"k?@a(?=bbb.~"
|
||||
"k?@a(?=bbbb~"
|
||||
"k?@a(?=bbbc~"
|
||||
"k?@a(?=bbbd~"
|
||||
"k?@a(?=bbbe~"
|
||||
"k?@a(?=bbbf~"
|
||||
"k?@a(?=bbbg~"
|
||||
"k?@a(?=bbbh~"
|
||||
"k?@a(?=bbbi~"
|
||||
"k?@a(?=bbbj~"
|
||||
"k?@a(?=bbbk~"
|
||||
"k?@a(?=bbbl~"
|
||||
"k?@a(?=bbbm~"
|
||||
"k?@a(?=bbbn~"
|
||||
"k?@a(?=bbbo~"
|
||||
"k?@a(?=bbbp~"
|
||||
"k?@a(?=bbbq~"
|
||||
"k?@a(?=bbbr~"
|
||||
"k?@a(?=bbbs~"
|
||||
"k?@a(?=bbbt~"
|
||||
"k?@a(?=bbbu~"
|
||||
"k?@a(?=bbbv~"
|
||||
"k?@a(?=bbbw~"
|
||||
"k?@a(?=bbbx~"
|
||||
"k?@a(?=bbby~"
|
||||
"k?@a(?=bbbz~"
|
||||
"k?@a(?=by?bC?:!k??????????????b~"
|
||||
"k?@a(?=by?bC?:!k??????????????c~"
|
||||
"k?@a(?=by?bC?:!k??????????????d~"
|
||||
"k?@a(?=by?bC?:!k??????????????e~"
|
||||
"k?@a(?=by?bC?:!k??????????????f~"
|
||||
"k?@a(?=by?bC?:!k??????????????g~"
|
||||
"k?@a(?=by?bC?:!k??????????????h~"
|
||||
"k?@a(?=by?bC?:!k??????????????i~"
|
||||
"k?@a(?=by?bC?:!k??????????????j~"
|
||||
"k?@a(?=by?bC?:!k??????????????k~"
|
||||
"k?@a(?=by?bC?:!k??????????????l~"
|
||||
"k?@a(?=by?bC?:!k??????????????m~"
|
||||
"k?@a(?=by?bC?:!k??????????????n~"
|
||||
"k?@a(?=by?bC?:!k??????????????o~"
|
||||
"k?@a(?=by?bC?:!k??????????????p~"
|
||||
"k?@a(?=by?bC?:!k??????????????q~"
|
||||
"k?@a(?=by?bC?:!k??????????????r~"
|
||||
"k?@a(?=by?bC?:!k??????????????s~"
|
||||
"k?@a(?=by?bC?:!k??????????????t~"
|
||||
"k?@a(?=by?bC?:!k??????????????u~"
|
||||
"k?@a(?=by?bC?:!k??????????????v~"
|
||||
"k?@a(?=by?bC?:!k??????????????w~"
|
||||
"k?@a(?=by?bC?:!k??????????????x~"
|
||||
"k?@a(?=by?bC?:!k??????????????y~"
|
||||
"k?@a(?=by?bC?:!k??????????????z~"
|
||||
"k?@a(?=by?bC?:!k???????????????~"
|
||||
"k?@a(?~"
|
||||
"k?@a(b~"
|
||||
"k?@a(c~"
|
||||
"k?@a(d~"
|
||||
"k?@a(e~"
|
||||
"k?@a(f~"
|
||||
"k?@a(g~"
|
||||
"k?@a(h~"
|
||||
"k?@a(i~"
|
||||
"k?@a(j~"
|
||||
"k?@a(k~"
|
||||
"k?@a(l~"
|
||||
"k?@a(m~"
|
||||
"k?@a(n~"
|
||||
"k?@a(o~"
|
||||
"k?@a(p~"
|
||||
"k?@a(q~"
|
||||
"k?@a(r~"
|
||||
"k?@a(s~"
|
||||
"k?@a(t~"
|
||||
"k?@a(u~"
|
||||
"k?@a(v~"
|
||||
"k?@a(w~"
|
||||
"k?@a(x~"
|
||||
"k?@a(y~"
|
||||
"k?@a(z~"
|
||||
"k0X@ab~"
|
||||
"k0X@ac~"
|
||||
"k0X@ad~"
|
||||
"k0X@ae~"
|
||||
"k0X@af~"
|
||||
"k0X@ag~"
|
||||
"k0X@ah~"
|
||||
"k0X@ai~"
|
||||
"k0X@aj~"
|
||||
"k0X@ak~"
|
||||
"k0X@al~"
|
||||
"k0X@am~"
|
||||
"k0X@an~"
|
||||
"k0X@ao~"
|
||||
"k0X@ap~"
|
||||
"k0X@aq~"
|
||||
"k0X@ar~"
|
||||
"k0X@as~"
|
||||
"k0X@at~"
|
||||
"k0X@au~"
|
||||
"k0X@av~"
|
||||
"k0X@aw~"
|
||||
"k0X@ax~"
|
||||
"k0X@ay~"
|
||||
"k0X@az~"
|
||||
"k0X@a?~"
|
||||
"k~"
|
||||
"l~"
|
||||
"m~"
|
||||
"n~"
|
||||
"o~"
|
||||
"p~"
|
||||
"q,}"
|
||||
"q~"
|
||||
"r~"
|
||||
"r?[c~]"
|
||||
"s~"
|
||||
"t~"
|
||||
"u0034,}"
|
||||
"u003z,}"
|
||||
"u0060,}"
|
||||
"ud808udf45*,}"
|
||||
"u~"
|
||||
"v~"
|
||||
"w"
|
||||
"w~"
|
||||
"x3z,}"
|
||||
"x60,}"
|
||||
"xyz?9"
|
||||
"x~"
|
||||
"y~"
|
||||
"z~"
|
||||
"{"
|
||||
"{??"
|
||||
"{ ,,?"
|
||||
"{-"
|
||||
"{0,d?????!"
|
||||
"{12345}pu{234:P}?"
|
||||
"{1?5"
|
||||
"{@"
|
||||
"{M,??"
|
||||
"{M,P{scx=Greek}???sn"
|
||||
"{M,??"
|
||||
"{M,??"
|
||||
"{M,?M,??"
|
||||
"{O"
|
||||
"{r~"
|
||||
"{s~"
|
||||
"{t~"
|
||||
"{u~"
|
||||
"{v~"
|
||||
"{w~"
|
||||
"{x~"
|
||||
"{y~"
|
||||
"{z~"
|
||||
"{}"
|
||||
"{}~"
|
||||
"{??@"
|
||||
"{?~"
|
||||
"},}"
|
||||
"}}"
|
||||
"}}}}}?}!}}}}}}}}}}}}}}}}}?},}"
|
||||
"}~"
|
||||
"}?w~???"
|
||||
"~~"
|
||||
"?!~"
|
||||
"?$"
|
||||
"?*?9?nnRnnn?"
|
||||
"?.~"
|
||||
"?123222222??"
|
||||
"?:??"
|
||||
"?R"
|
||||
"?b~"
|
||||
"?c~"
|
||||
"?d~"
|
||||
"?d???"
|
||||
"?e~"
|
||||
"?f~"
|
||||
"?g~"
|
||||
"?h~"
|
||||
"?i~"
|
||||
"?j~"
|
||||
"?k~"
|
||||
"?l~"
|
||||
"?m~"
|
||||
"?n~"
|
||||
"?o~"
|
||||
"?p~"
|
||||
"?q~"
|
||||
"?r~"
|
||||
"?s~"
|
||||
"?t~"
|
||||
"?u~"
|
||||
"?v~"
|
||||
"?v~?v"
|
||||
"?w~"
|
||||
"?x~"
|
||||
"?y~"
|
||||
"?z~"
|
||||
"?}"
|
||||
"??~"
|
||||
"?????????dadi(?!bbb"
|
||||
"??~"
|
||||
"k?@a??=bbC?:!k?x!k0}??@???@a(P=b@??s@xxq~>>>>>>>>>>>>>>>>>>"
|
||||
"?f??123222222??"
|
||||
"?fP{gc=Decimal_Number}"
|
||||
"?f2jq?oo@ooooh??"
|
||||
"?[???],}f?"
|
||||
"?[???],}nbbc2jocom"
|
||||
"?[]"
|
||||
"?[],}?"
|
||||
"?[],}f?"
|
||||
"?[]f?"
|
||||
"?[]{}()%^#"
|
||||
"?[^123],}f?"
|
||||
"?[^123]nbbc2jocom"
|
||||
"?[a-b-c],}f?"
|
||||
"?[a-b-c]nbbc2jocom"
|
||||
"?[a-zA-Z0-9],}f?"
|
||||
"?[a-zA-Z0-9],}jocom"
|
||||
"?[a-zA-Z0-9]c2jocom"
|
||||
"?[bfoo(?!bar)bazcom"
|
||||
"?[bfoo(?!bar)bazf?"
|
||||
"(?:a?)??"
|
||||
"a?)"xyz{93}"
|
||||
"{93}"
|
||||
@ -601,3 +245,12 @@
|
||||
"[\x8f]"
|
||||
"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\x92\xa9-\xf4\x8f\xbf\xbf]"
|
||||
"[\x92\xa9-\xf4\x8f\xbf\xbf]"
|
||||
"\\1\\2(b\\1\\2))\\2)\\1"
|
||||
"\\1\\2(a(?:\\1\\2))\\2)\\1"
|
||||
"?:\\1"
|
||||
"\\1(b\\1\\2))\\2)\\1"
|
||||
"\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1"
|
||||
"foo(?=bar)bar)baz"
|
||||
"fo(?o(?o(?o(?=bar)baz"
|
||||
"foo(?=bar)baz"
|
||||
"foo(?=bar)bar)az"
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
This is the list of all noteworthy changes made in every public release of
|
||||
the tool. See README for the general instruction manual.
|
||||
the tool. See README.md for the general instruction manual.
|
||||
|
||||
## Staying informed
|
||||
|
||||
@ -9,6 +9,69 @@ 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.63c (release):
|
||||
|
||||
! the repository was moved from vanhauser-thc to AFLplusplus. It is now
|
||||
an own organisation :)
|
||||
! development and acceptance of PRs now happen only in the dev branch
|
||||
and only occasionally when everything is fine we PR to master
|
||||
- all:
|
||||
- big code changes to make afl-fuzz thread-safe so afl-fuzz can spawn
|
||||
multiple fuzzing threads in the future or even become a library
|
||||
- afl basic tools now report on the environment variables picked up
|
||||
- more tools get environment variable usage info in the help output
|
||||
- force all output to stdout (some OK/SAY/WARN messages were sent to
|
||||
stdout, some to stderr)
|
||||
- uninstrumented mode uses an internal forkserver ("fauxserver")
|
||||
- now builds with `-D_FORTIFY_SOURCE=2`
|
||||
- drastically reduced number of (de)allocations during fuzzing
|
||||
- afl-fuzz:
|
||||
- python mutator modules and custom mutator modules now use the same
|
||||
interface and hence the API changed
|
||||
- AFL_AUTORESUME will resume execution without the need to specify `-i -`
|
||||
- added experimental power schedules (-p):
|
||||
- mmopt: ignores runtime of queue entries, gives higher weighting to
|
||||
the last 5 queue entries
|
||||
- rare: puts focus on queue entries that hits rare branches, also ignores
|
||||
runtime
|
||||
- llvm_mode:
|
||||
- added SNAPSHOT feature (using https://github.com/AFLplusplus/AFL-Snapshot-LKM)
|
||||
- added Control Flow Integrity sanitizer (AFL_USE_CFISAN)
|
||||
- added AFL_LLVM_INSTRUMENT option to control the instrumentation type
|
||||
easier: DEFAULT, CFG (INSTRIM), LTO, CTX, NGRAM-x (x=2-16)
|
||||
- made USE_TRACE_PC compile obsolete
|
||||
- LTO collision free instrumented added in llvm_mode with afl-clang-lto -
|
||||
note that this mode is amazing, but quite some targets won't compile
|
||||
- Added llvm_mode NGRAM prev_loc coverage by Adrean Herrera
|
||||
(https://github.com/adrianherrera/afl-ngram-pass/), activate by setting
|
||||
AFL_LLVM_INSTRUMENT=NGRAM-<value> or AFL_LLVM_NGRAM_SIZE=<value>
|
||||
- Added llvm_mode context sensitive branch coverage, activated by setting
|
||||
AFL_LLVM_INSTRUMENT=CTX or AFL_LLVM_CTX=1
|
||||
- llvm_mode InsTrim mode:
|
||||
- removed workaround for bug where paths were not instrumented and
|
||||
imported fix by author
|
||||
- made skipping 1 block functions an option and is disabled by default,
|
||||
set AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 to re-enable this
|
||||
- qemu_mode:
|
||||
- qemu_mode now uses solely the internal capstone version to fix builds
|
||||
on modern Linux distributions
|
||||
- QEMU now logs routine arguments for CmpLog when the target is x86
|
||||
- afl-tmin:
|
||||
- now supports hang mode `-H` to minimize hangs
|
||||
- fixed potential afl-tmin missbehavior for targets with multiple hangs
|
||||
- Pressing Control-c in afl-cmin did not terminate it for some OS
|
||||
- the custom API was rewritten and is now the same for Python and shared
|
||||
libraries.
|
||||
|
||||
|
||||
### Version ++2.62c (release):
|
||||
|
||||
- Important fix for memory allocation functions that result in afl-fuzz
|
||||
not identifying crashes - UPDATE!
|
||||
- Small fix for -E/-V to release the CPU
|
||||
- CmpLog does not need sancov anymore
|
||||
|
||||
|
||||
### Version ++2.61c (release):
|
||||
|
||||
- use -march=native if available
|
||||
@ -40,7 +103,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- now does not need to be recompiled between trace-pc and pass
|
||||
instrumentation. compile normally and set AFL_LLVM_USE_TRACE_PC :)
|
||||
- LLVM 11 is supported
|
||||
- CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog)
|
||||
- CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog.md)
|
||||
- afl-gcc, afl-clang-fast, afl-gcc-fast:
|
||||
- experimental support for undefined behaviour sanitizer UBSAN
|
||||
(set AFL_USE_UBSAN=1)
|
||||
@ -152,7 +215,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
- big code refactoring:
|
||||
* all includes are now in include/
|
||||
* all afl sources are now in src/ - see src/README.src
|
||||
* all afl sources are now in src/ - see src/README.md
|
||||
* afl-fuzz was splitted up in various individual files for including
|
||||
functionality in other programs (e.g. forkserver, memory map, etc.)
|
||||
for better readability.
|
||||
@ -184,7 +247,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- fix llvm_mode AFL_TRACE_PC with modern llvm
|
||||
- fix a crash in qemu_mode which also exists in stock afl
|
||||
- added libcompcov, a laf-intel implementation for qemu! :)
|
||||
see qemu_mode/libcompcov/README.libcompcov
|
||||
see qemu_mode/libcompcov/README.libcompcov.md
|
||||
- afl-fuzz now displays the selected core in the status screen (blue {#})
|
||||
- updated afl-fuzz and afl-system-config for new scaling governor location
|
||||
in modern kernels
|
||||
@ -193,8 +256,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- if llvm_mode was compiled, afl-clang/afl-clang++ will point to these
|
||||
instead of afl-gcc
|
||||
- added instrim, a much faster llvm_mode instrumentation at the cost of
|
||||
path discovery. See llvm_mode/README.instrim (https://github.com/csienslab/instrim)
|
||||
- added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt
|
||||
path discovery. See llvm_mode/README.instrim.md (https://github.com/csienslab/instrim)
|
||||
- added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt.md
|
||||
- added code to make it more portable to other platforms than Intel Linux
|
||||
- added never zero counters for afl-gcc and optionally (because of an
|
||||
optimization issue in llvm < 9) for llvm_mode (AFL_LLVM_NEVER_ZERO=1)
|
||||
@ -224,11 +287,11 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
LLVM and Qemu modes are now faster.
|
||||
Important changes:
|
||||
afl-fuzz: -e EXTENSION commandline option
|
||||
llvm_mode: LAF-intel performance (needs activation, see llvm/README.laf-intel)
|
||||
a few new environment variables for afl-fuzz, llvm and qemu, see docs/env_variables.txt
|
||||
llvm_mode: LAF-intel performance (needs activation, see llvm/README.laf-intel.md)
|
||||
a few new environment variables for afl-fuzz, llvm and qemu, see docs/env_variables.md
|
||||
- Added the power schedules of AFLfast by Marcel Boehme, but set the default
|
||||
to the AFL schedule, not to the FAST schedule. So nothing changes unless
|
||||
you use the new -p option :-) - see docs/power_schedules.txt
|
||||
you use the new -p option :-) - see docs/power_schedules.md
|
||||
- added afl-system-config script to set all system performance options for fuzzing
|
||||
- llvm_mode works with llvm 3.9 up to including 8 !
|
||||
- qemu_mode got upgraded from 2.1 to 3.1 - incorporated from
|
||||
@ -471,7 +534,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- Added libtokencap, a simple feature to intercept strcmp / memcmp and
|
||||
generate dictionary entries that can help extend coverage.
|
||||
|
||||
- Moved libdislocator to its own dir, added README.
|
||||
- Moved libdislocator to its own dir, added README.md.
|
||||
|
||||
- The demo in examples/instrumented_cmp is no more.
|
||||
|
||||
|
@ -20,6 +20,7 @@ afl-qemu-speed.diff by abiondo on github
|
||||
afl-qemu-optimize-map.diff by mh(at)mh-sec(dot)de
|
||||
```
|
||||
|
||||
+ llvm_mode ngram prev_loc coverage (github.com/adrianherrera/afl-ngram-pass)
|
||||
+ Custom mutator (native library) (by kyakdan)
|
||||
+ unicorn_mode (modernized and updated by domenukk)
|
||||
+ instrim (https://github.com/csienslab/instrim) was integrated
|
||||
|
@ -27,7 +27,7 @@ how to hit the ground running:
|
||||
|
||||
4) Get a small but valid input file that makes sense to the program. When
|
||||
fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described in
|
||||
dictionaries/README.dictionaries, too.
|
||||
dictionaries/README.md, too.
|
||||
|
||||
5) If the program reads from stdin, run 'afl-fuzz' like so:
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# american fuzzy lop plus plus (afl++)
|
||||
|
||||

|
||||

|
||||
|
||||
Release Version: 2.60c
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
Originally developed by Michal "lcamtuf" Zalewski.
|
||||
|
||||
Repository: [https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
afl++ is maintained by Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
||||
Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
|
||||
@ -75,7 +75,7 @@
|
||||
So all in all this is the best-of afl that is currently out there :-)
|
||||
|
||||
For new versions and additional information, check out:
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
To compare notes with other users or get notified about major new features,
|
||||
send a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
@ -675,7 +675,7 @@ Thank you!
|
||||
## 16) Contact
|
||||
|
||||
Questions? Concerns? Bug reports? The contributors can be reached via
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
There is also a mailing list for the afl project; to join, send a mail to
|
||||
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse
|
||||
|
@ -148,7 +148,7 @@
|
||||
There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer)
|
||||
|
||||
There is also an early implementation in an AFL++ test branch:
|
||||
[https://github.com/vanhauser-thc/AFLplusplus/tree/frida](https://github.com/vanhauser-thc/AFLplusplus/tree/frida)
|
||||
[https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida)
|
||||
|
||||
|
||||
## PIN & DYNAMORIO
|
||||
|
@ -1,36 +0,0 @@
|
||||
# Adding custom mutators to AFL
|
||||
|
||||
This file describes how you can implement custom mutations to be used in AFL.
|
||||
|
||||
Implemented by Khaled Yakdan from Code Intelligence <yakdan@code-intelligence.de>
|
||||
|
||||
## 1) Description
|
||||
|
||||
Custom mutator libraries can be passed to afl-fuzz to perform custom mutations
|
||||
on test cases beyond those available in AFL - for example, to enable structure-aware
|
||||
fuzzing by using libraries that perform mutations according to a given grammar.
|
||||
|
||||
The custom mutator library is passed to afl-fuzz via the AFL_CUSTOM_MUTATOR_LIBRARY
|
||||
environment variable. The library must export the afl_custom_mutator() function and
|
||||
must be compiled as a shared object. For example:
|
||||
$CC -shared -Wall -O3 <lib-name>.c -o <lib-name>.so
|
||||
|
||||
Note: unless AFL_CUSTOM_MUTATOR_ONLY is set, its state mutator like any others,
|
||||
so it will be used for some test cases, and other mutators for others.
|
||||
|
||||
Only if AFL_CUSTOM_MUTATOR_ONLY is set the afl_custom_mutator() function will
|
||||
be called every time it needs to mutate test case!
|
||||
|
||||
For some cases, the format of the mutated data returned from
|
||||
the custom mutator is not suitable to directly execute the target with this input.
|
||||
For example, when using libprotobuf-mutator, the data returned is in a protobuf
|
||||
format which corresponds to a given grammar. In order to execute the target,
|
||||
the protobuf data must be converted to the plain-text format expected by the target.
|
||||
In such scenarios, the user can define the afl_pre_save_handler() function. This function
|
||||
is then transforms the data into the format expected by the API before executing the target.
|
||||
afl_pre_save_handler is optional and does not have to be implemented if its functionality
|
||||
is not needed.
|
||||
|
||||
## 2) Example
|
||||
|
||||
A simple example is provided in ../examples/custom_mutators/
|
239
docs/custom_mutators.md
Normal file
239
docs/custom_mutators.md
Normal file
@ -0,0 +1,239 @@
|
||||
# Custom Mutators in AFL++
|
||||
|
||||
This file describes how you can implement custom mutations to be used in AFL.
|
||||
For now, we support C/C++ library and Python module, collectivelly named as the
|
||||
custom mutator.
|
||||
|
||||
Implemented by
|
||||
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
||||
- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
Custom mutators can be passed to `afl-fuzz` to perform custom mutations on test
|
||||
cases beyond those available in AFL. For example, to enable structure-aware
|
||||
fuzzing by using libraries that perform mutations according to a given grammar.
|
||||
|
||||
The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY`
|
||||
or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function.
|
||||
Please see [APIs](#2-apis) and [Usage](#3-usage) for detail.
|
||||
|
||||
The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage).
|
||||
|
||||
Note: If `AFL_CUSTOM_MUTATOR_ONLY` is set, all mutations will solely be
|
||||
performed with the custom mutator.
|
||||
|
||||
## 2) APIs
|
||||
|
||||
C/C++:
|
||||
```c
|
||||
void *afl_custom_init(afl_t *afl, unsigned int seed);
|
||||
size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size);
|
||||
size_t afl_custom_pre_save(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) {
|
||||
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); void afl_custom_queue_new_entry(void *data, const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue);
|
||||
void afl_custom_deinit(void *data);
|
||||
```
|
||||
|
||||
Python:
|
||||
```python
|
||||
def init(seed):
|
||||
pass
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
return mutated_out
|
||||
|
||||
def pre_save(buf):
|
||||
return out_buf
|
||||
|
||||
def init_trim(buf):
|
||||
return cnt
|
||||
|
||||
def trim():
|
||||
return out_buf
|
||||
|
||||
def post_trim(success):
|
||||
return next_index
|
||||
|
||||
def havoc_mutation(buf, max_size):
|
||||
return mutated_out
|
||||
|
||||
def havoc_mutation_probability():
|
||||
return probability # int in [0, 100]
|
||||
|
||||
def queue_get(filename):
|
||||
return True
|
||||
|
||||
def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
pass
|
||||
```
|
||||
|
||||
### Custom Mutation
|
||||
|
||||
- `init`:
|
||||
|
||||
This method is called when AFL++ starts up and is used to seed RNG and set up buffers and state.
|
||||
|
||||
- `queue_get` (optional):
|
||||
|
||||
This method determines whether the fuzzer should fuzz the current queue
|
||||
entry or not
|
||||
|
||||
- `fuzz` (required):
|
||||
|
||||
This method performs custom mutations on a given input. It also accepts an
|
||||
additional test case.
|
||||
|
||||
- `havoc_mutation` and `havoc_mutation_probability` (optional):
|
||||
|
||||
`havoc_mutation` performs a single custom mutation on a given input. This
|
||||
mutation is stacked with the other mutations in havoc. The other method,
|
||||
`havoc_mutation_probability`, returns the probability that `havoc_mutation`
|
||||
is called in havoc. By default, it is 6%.
|
||||
|
||||
- `pre_save` (optional):
|
||||
|
||||
For some cases, the format of the mutated data returned from the custom
|
||||
mutator is not suitable to directly execute the target with this input.
|
||||
For example, when using libprotobuf-mutator, the data returned is in a
|
||||
protobuf format which corresponds to a given grammar. In order to execute
|
||||
the target, the protobuf data must be converted to the plain-text format
|
||||
expected by the target. In such scenarios, the user can define the
|
||||
`pre_save` function. This function is then transforms the data into the
|
||||
format expected by the API before executing the target.
|
||||
|
||||
- `queue_new_entry` (optional):
|
||||
|
||||
This methods is called after adding a new test case to the queue.
|
||||
|
||||
### Trimming Support
|
||||
|
||||
The generic trimming routines implemented in AFL++ can easily destroy the
|
||||
structure of complex formats, possibly leading to a point where you have a lot
|
||||
of test cases in the queue that your Python module cannot process anymore but
|
||||
your target application still accepts. This is especially the case when your
|
||||
target can process a part of the input (causing coverage) and then errors out
|
||||
on the remaining input.
|
||||
|
||||
In such cases, it makes sense to implement a custom trimming routine. The API
|
||||
consists of multiple methods because after each trimming step, we have to go
|
||||
back into the C code to check if the coverage bitmap is still the same for the
|
||||
trimmed input. Here's a quick API description:
|
||||
|
||||
- `init_trim` (optional):
|
||||
|
||||
This method is called at the start of each trimming operation and receives
|
||||
the initial buffer. It should return the amount of iteration steps possible
|
||||
on this input (e.g. if your input has n elements and you want to remove them
|
||||
one by one, return n, if you do a binary search, return log(n), and so on).
|
||||
|
||||
If your trimming algorithm doesn't allow you to determine the amount of
|
||||
(remaining) steps easily (esp. while running), then you can alternatively
|
||||
return 1 here and always return 0 in `post_trim` until you are finished and
|
||||
no steps remain. In that case, returning 1 in `post_trim` will end the
|
||||
trimming routine. The whole current index/max iterations stuff is only used
|
||||
to show progress.
|
||||
|
||||
- `trim` (optional)
|
||||
|
||||
This method is called for each trimming operation. It doesn't have any
|
||||
arguments because we already have the initial buffer from `init_trim` and we
|
||||
can memorize the current state in the data variables. This can also save
|
||||
reparsing steps for each iteration. It should return the trimmed input
|
||||
buffer, where the returned data must not exceed the initial input data in
|
||||
length. Returning anything that is larger than the original data (passed to
|
||||
`init_trim`) will result in a fatal abort of AFL++.
|
||||
|
||||
- `post_trim` (optional)
|
||||
|
||||
This method is called after each trim operation to inform you if your
|
||||
trimming step was successful or not (in terms of coverage). If you receive
|
||||
a failure here, you should reset your input to the last known good state.
|
||||
In any case, this method must return the next trim iteration index (from 0
|
||||
to the maximum amount of steps you returned in `init_trim`).
|
||||
|
||||
`deinit` the last method to be called, deinitializing the state.
|
||||
|
||||
Omitting any of three methods will cause the trimming to be disabled and trigger
|
||||
a fallback to the builtin default trimming routine.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Optionally, the following environment variables are supported:
|
||||
|
||||
- `AFL_CUSTOM_MUTATOR_ONLY`
|
||||
|
||||
Disable all other mutation stages. This can prevent broken testcases
|
||||
(those that your Python module can't work with anymore) to fill up your
|
||||
queue. Best combined with a custom trimming routine (see below) because
|
||||
trimming can cause the same test breakage like havoc and splice.
|
||||
|
||||
|
||||
- `AFL_PYTHON_ONLY`
|
||||
|
||||
Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead
|
||||
trimming can cause the same test breakage like havoc and splice.
|
||||
|
||||
- `AFL_DEBUG`
|
||||
|
||||
When combined with `AFL_NO_UI`, this causes the C trimming code to emit additional messages about the performance and actions of your custom trimmer. Use this to see if it works :)
|
||||
|
||||
## 3) Usage
|
||||
|
||||
### Prerequisite
|
||||
|
||||
For Python mutator, the python 3 or 2 development package is required. On
|
||||
Debian/Ubuntu/Kali this can be done:
|
||||
|
||||
```bash
|
||||
sudo apt install python3-dev
|
||||
# or
|
||||
sudo apt install python-dev
|
||||
```
|
||||
|
||||
Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects
|
||||
Python 2 and 3 through `python-config` if it is in the PATH and compiles
|
||||
`afl-fuzz` with the feature if available.
|
||||
|
||||
Note: for some distributions, you might also need the package `python[23]-apt`.
|
||||
In case your setup is different, set the necessary variables like this:
|
||||
`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
|
||||
|
||||
### Custom Mutator Preparation
|
||||
|
||||
For C/C++ mutator, the source code must be compiled as a shared object:
|
||||
```bash
|
||||
gcc -shared -Wall -O3 example.c -o example.so
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
C/C++
|
||||
```bash
|
||||
export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so
|
||||
afl-fuzz /path/to/program
|
||||
```
|
||||
|
||||
Python
|
||||
```bash
|
||||
export PYTHONPATH=`dirname /full/path/to/example.py`
|
||||
export AFL_PYTHON_MODULE=example
|
||||
afl-fuzz /path/to/program
|
||||
```
|
||||
|
||||
## 4) Example
|
||||
|
||||
Please see [example.c](../examples/custom_mutators/example.c) and
|
||||
[example.py](../examples/custom_mutators/example.py)
|
||||
|
||||
## 5) Other Resources
|
||||
|
||||
- AFL libprotobuf mutator
|
||||
- [bruce30262/libprotobuf-mutator_fuzzing_learning](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
||||
- [thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
||||
- [XML Fuzzing@NullCon 2017](https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf)
|
||||
- [A bug detected by AFL + XML-aware mutators](https://bugs.chromium.org/p/chromium/issues/detail?id=930663)
|
@ -2,7 +2,7 @@
|
||||
|
||||
This document discusses the environment variables used by American Fuzzy Lop++
|
||||
to expose various exotic functions that may be (rarely) useful for power
|
||||
users or for some types of custom fuzzing setups. See README for the general
|
||||
users or for some types of custom fuzzing setups. See README.md for the general
|
||||
instruction manual.
|
||||
|
||||
## 1) Settings for afl-gcc, afl-clang, and afl-as - and gcc_plugin afl-gcc-fast
|
||||
@ -31,7 +31,9 @@ tools make fairly broad use of environmental variables:
|
||||
|
||||
(You can also enable MSAN via AFL_USE_MSAN; ASAN and MSAN come with the
|
||||
same gotchas; the modes are mutually exclusive. UBSAN can be enabled
|
||||
similarly by setting the environment variable AFL_USE_UBSAN=1)
|
||||
similarly by setting the environment variable AFL_USE_UBSAN=1. Finally
|
||||
there is the Control Flow Integrity sanitizer that can be activated by
|
||||
AFL_USE_CFISAN=1)
|
||||
|
||||
- Setting AFL_CC, AFL_CXX, and AFL_AS lets you use alternate downstream
|
||||
compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
|
||||
@ -91,6 +93,76 @@ of the settings discussed in section #1, with the exception of:
|
||||
|
||||
Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
### Select the instrumentation mode
|
||||
|
||||
- AFL_LLVM_INSTRUMENT - this configures the instrumentation mode.
|
||||
Available options:
|
||||
DEFAULT - classic AFL (map[cur_loc ^ prev_loc >> 1]++)
|
||||
CFG - InsTrim instrumentation (see below)
|
||||
LTO - LTO instrumentation (see below)
|
||||
CTX - context sensitive instrumentation (see below)
|
||||
NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
|
||||
Only one can be used.
|
||||
|
||||
### LTO
|
||||
|
||||
This is a different kind way of instrumentation: first it compiles all
|
||||
code in LTO (link time optimization) and then performs an edge inserting
|
||||
instrumentation which is 100% collision free (collisions are a big issue
|
||||
in afl and afl-like instrumentations). This is performed by using
|
||||
afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only
|
||||
built if LLVM 9 or newer is used.
|
||||
|
||||
None of these 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_LTO_STARTID sets the starting location ID for the instrumentation.
|
||||
This defaults to 1
|
||||
- AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written
|
||||
into the instrumentation is set in a global variable
|
||||
|
||||
See llvm_mode/README.LTO.md for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
This feature increases the speed by ~15% without any disadvantages.
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM_LOOPHEAD=1 expands on INSTRIM to optimize loops.
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 will skip instrumenting
|
||||
functions with a single basic block. This is useful for most C and
|
||||
some C++ targets.
|
||||
|
||||
See llvm_mode/README.instrim.md
|
||||
|
||||
### NGRAM
|
||||
|
||||
- Setting AFL_LLVM_NGRAM_SIZE or AFL_LLVM_INSTRUMENT=NGRAM-{value}
|
||||
activates ngram prev_loc coverage, good values are 2, 4 or 8
|
||||
(any value between 2 and 16 is valid).
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ctx.md
|
||||
|
||||
### CTX
|
||||
|
||||
- Setting AFL_LLVM_CTX or AFL_LLVM_INSTRUMENT=CTX
|
||||
activates context sensitive branch coverage - meaning that each edge
|
||||
is additionally combined with its caller.
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ngram.md
|
||||
|
||||
### LAF-INTEL
|
||||
|
||||
This great feature will split compares to series of single byte comparisons
|
||||
@ -115,19 +187,6 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
See llvm_mode/README.whitelist.md for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
This feature increases the speed by whopping 20% but at the cost of a
|
||||
lower path discovery and therefore coverage.
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM activates this mode
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM_LOOPHEAD=1 expands on INSTRIM to optimize loops.
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
See llvm_mode/README.instrim.md
|
||||
|
||||
### NOT_ZERO
|
||||
|
||||
- Setting AFL_LLVM_NOT_ZERO=1 during compilation will use counters
|
||||
@ -198,6 +257,9 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics.
|
||||
This can be useful to speed up the fuzzing of text-based file formats.
|
||||
|
||||
- AFL_NO_SNAPSHOT will advice afl-fuzz not to use the snapshot feature
|
||||
if the snapshot lkm is loaded
|
||||
|
||||
- AFL_SHUFFLE_QUEUE randomly reorders the input queue on startup. Requested
|
||||
by some users for unorthodox parallelized fuzzing setups, but not
|
||||
advisable otherwise.
|
||||
@ -223,14 +285,15 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
for more.
|
||||
|
||||
- Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with
|
||||
afl_custom_mutator() export run additional mutations though this library.
|
||||
afl_custom_fuzz() creates additional mutations through this library.
|
||||
If afl-fuzz is compiled with Python (which is autodetected during builing
|
||||
afl-fuzz), setting AFL_PYTHON_MODULE to a Python module can also provide
|
||||
additional mutations.
|
||||
If AFL_CUSTOM_MUTATOR_ONLY is also set, all mutations will solely be
|
||||
performed with/from the libary. see [custom_mutator.md](custom_mutator.md)
|
||||
|
||||
- For AFL_PYTHON_MODULE and AFL_PYTHON_ONLY - they require to be compiled
|
||||
with -DUSE_PYTHON. Please see [python_mutators.md](python_mutators.md)
|
||||
This feature allows to configure custom mutators which can be very helpful
|
||||
in e.g. fuzzing XML or other highly flexible structured input.
|
||||
performed with the custom mutator.
|
||||
This feature allows to configure custom mutators which can be very helpful,
|
||||
e.g. fuzzing XML or other highly flexible structured input.
|
||||
Please see [custom_mutators.md](custom_mutators.md).
|
||||
|
||||
- AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less
|
||||
precise), which can help when starting a session against a slow target.
|
||||
@ -262,6 +325,16 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Setting AFL_DEBUG_CHILD_OUTPUT will not suppress the child output.
|
||||
Not pretty but good for debugging purposes.
|
||||
|
||||
- Setting AFL_NO_CPU_RED will not display very high cpu usages in red color.
|
||||
|
||||
- Setting AFL_AUTORESUME will resume a fuzz run (same as providing `-i -`)
|
||||
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.
|
||||
|
||||
- Outdated environment variables that are that not supported anymore:
|
||||
AFL_DEFER_FORKSRV
|
||||
AFL_PERSISTENT
|
||||
|
||||
## 4) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
@ -408,3 +481,4 @@ optimal values if not already present in the environment:
|
||||
Be sure to include the first one when customizing anything, since some
|
||||
MSAN versions don't call abort() on error, and we need a way to detect
|
||||
faults.
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
# Ideas for afl++
|
||||
|
||||
In the following, we describe a variety of ideas that could be implemented for further AFL++ versions.
|
||||
In the following, we describe a variety of ideas that could be implemented
|
||||
for future AFL++ versions.
|
||||
|
||||
For GSOC2020 interested students please see
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues/208](https://github.com/AFLplusplus/AFLplusplus/issues/208)
|
||||
|
||||
## Flexible Grammar Mutator
|
||||
|
||||
@ -19,6 +23,8 @@ common issues of the academic code.
|
||||
We aim to develop a pluggable grammar mutator for afl++ that combines
|
||||
various results.
|
||||
|
||||
Mentor: andreafioraldi
|
||||
|
||||
## Expand on the MOpt mutator
|
||||
|
||||
Work on the MOpt mutator that is already in AFL++.
|
||||
@ -27,11 +33,27 @@ This is an excellent mutations scheduler based on Particle Swarm
|
||||
Optimization but the current implementation schedule only the mutations
|
||||
that were present on AFL.
|
||||
|
||||
AFL++ added a lost of optional mutators like the Input-2-State one based
|
||||
AFL++ added a lot of optional mutators like the Input-2-State one based
|
||||
on Redqueen, the Radamsa mutator, the Custom mutator (the user can define
|
||||
its own mutator) and the work is to generalize MOpt for all the current
|
||||
and future mutators.
|
||||
|
||||
Mentor: vanhauser-thc or andreafioraldi
|
||||
|
||||
## perf-fuzz Linux Kernel Module
|
||||
|
||||
Either Port the patch to the upcoming Ubuntu LTS 20.04 default kernel
|
||||
and provide a qemu-kvm image or find a different userspace snapshot
|
||||
solution that has a good performance and is reliable, e.g. with docker.
|
||||
[perf-fuzz](https://gts3.org/assets/papers/2017/xu:os-fuzz.pdf)
|
||||
The perf-fuzz kernel can be found at [https://github.com/sslab-gatech/perf-fuzz](https://github.com/sslab-gatech/perf-fuzz)
|
||||
There also is/was a FreeBSD project at [https://github.com/veracode-research/freebsd-perf-fuzz](https://github.com/veracode-research/freebsd-perf-fuzz)
|
||||
|
||||
This enables snapshot fuzzing on Linux with an incredible performance!
|
||||
|
||||
Mentor: any
|
||||
Idea/Issue tracker: [https://github.com/AFLplusplus/AFLplusplus/issues/248](https://github.com/AFLplusplus/AFLplusplus/issues/248)
|
||||
|
||||
## QEMU 4-based Instrumentation
|
||||
|
||||
First tests to use QEMU 4 for binary-only AFL++ showed that caching behavior
|
||||
@ -42,6 +64,8 @@ This is the cause why, right now, we cannot switch to QEMU 4.2.
|
||||
Understanding the current instrumentation and fixing the current caching
|
||||
issues will be needed.
|
||||
|
||||
Mentor: andreafioraldi
|
||||
|
||||
## WASM Instrumentation
|
||||
|
||||
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
|
||||
@ -51,24 +75,46 @@ This can either be done by inserting instrumentation directly into the
|
||||
WASM AST, or by patching feedback into a WASM VMs of choice, similar to
|
||||
the current Unicorn instrumentation.
|
||||
|
||||
Mentor: any
|
||||
|
||||
## Machine Learning
|
||||
|
||||
Something with machine learning, better than NEUZZ :-)
|
||||
Either improve a single mutator thorugh learning of many different bugs (a bug class) or gather deep insights about a single target beforehand (CFG, DFG, VFG, ...?) and improve performance for a single target.
|
||||
Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-)
|
||||
Either improve a single mutator thorugh learning of many different bugs
|
||||
(a bug class) or gather deep insights about a single target beforehand
|
||||
(CFG, DFG, VFG, ...?) and improve performance for a single target.
|
||||
|
||||
Mentor: domenukk
|
||||
|
||||
## Reengineer `afl-fuzz` as Thread Safe, Embeddable Library
|
||||
|
||||
Right now, afl-fuzz is single threaded, cannot safely be embedded in tools, and not multi-threaded. It makes use of a large number of globals, must always be the parent process and exec child processes.
|
||||
Right now, afl-fuzz is single threaded, cannot safely be embedded in tools,
|
||||
and not multi-threaded. It makes use of a large number of globals, must always
|
||||
be the parent process and exec child processes.
|
||||
Instead, afl-fuzz could be refactored to contain no global state and globals.
|
||||
This allows for different use cases that could be implemented during this project.
|
||||
This allows for different use cases that could be implemented during this
|
||||
project.
|
||||
Note that in the mean time a lot has happened here already, but e.g. making
|
||||
it all work and implement multithreading in afl-fuzz ... there is still quite
|
||||
some work to do.
|
||||
|
||||
Mentor: hexcoder- or vanhauser-thc
|
||||
|
||||
## Collision-free Binary-Only Maps
|
||||
|
||||
AFL++ supports collison-free maps using an LTO (link-time-optimization) pass.
|
||||
This should be possile to implement for QEMU and Unicorn instrumentations.
|
||||
As the forkserver parent caches just in time translated translation blocks, adding a simple counter between jumps should be doable.
|
||||
This should be possible to implement for QEMU and Unicorn instrumentations.
|
||||
As the forkserver parent caches just in time translated translation blocks,
|
||||
adding a simple counter between jumps should be doable.
|
||||
|
||||
Note: this is already in development for qemu by Andrea, so for people who
|
||||
want to contribute it might make more sense to port his solution to unicorn.
|
||||
|
||||
Mentor: andreafioraldi or domenukk
|
||||
Issue/idea tracker: [https://github.com/AFLplusplus/AFLplusplus/issues/237](https://github.com/AFLplusplus/AFLplusplus/issues/237)
|
||||
|
||||
## Your idea!
|
||||
|
||||
Finally, we are open to proposals!
|
||||
Create an issue at https://github.com/vanhauser-thc/AFLplusplus/issues and let's discuss :-)
|
||||
Create an issue at https://github.com/AFLplusplus/AFLplusplus/issues and let's discuss :-)
|
||||
|
||||
|
@ -62,7 +62,7 @@ Specify `AFL_HARDEN=1` in the environment to enable hardening flags.
|
||||
|
||||
## Bumping into problems with non-reproducible crashes?
|
||||
It happens, but usually
|
||||
isn't hard to diagnose. See section #7 in README for tips.
|
||||
isn't hard to diagnose. See section #7 in README.md for tips.
|
||||
|
||||
## Fuzzing is not just about memory corruption issues in the codebase.
|
||||
Add some
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Notes for using ASAN with afl-fuzz
|
||||
|
||||
This file discusses some of the caveats for fuzzing under ASAN, and suggests
|
||||
a handful of alternatives. See README for the general instruction manual.
|
||||
a handful of alternatives. See README.md for the general instruction manual.
|
||||
|
||||
## 1) Short version
|
||||
|
||||
@ -28,6 +28,10 @@ Note that ASAN is incompatible with -static, so be mindful of that.
|
||||
|
||||
(You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
|
||||
|
||||
NOTE: if you run several slaves only one should run the target compiled with
|
||||
ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers
|
||||
compiled in.
|
||||
|
||||
There is also the option of generating a corpus using a non-ASAN binary, and
|
||||
then feeding it to an ASAN-instrumented one to check for bugs. This is faster,
|
||||
and can give you somewhat comparable results. You can also try using
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Tips for parallel fuzzing
|
||||
|
||||
This document talks about synchronizing afl-fuzz jobs on a single machine
|
||||
or across a fleet of systems. See README for the general instruction manual.
|
||||
or across a fleet of systems. See README.md for the general instruction manual.
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
## Tips for performance optimization
|
||||
|
||||
This file provides tips for troubleshooting slow or wasteful fuzzing jobs.
|
||||
See README for the general instruction manual.
|
||||
See README.md for the general instruction manual.
|
||||
|
||||
## 1. Keep your test cases small
|
||||
|
||||
|
@ -19,6 +19,8 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ
|
||||
| `-p quad` |  |
|
||||
| `-p lin` |  |
|
||||
| `-p exploit` (AFL) |  |
|
||||
| `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries |
|
||||
| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges |
|
||||
where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path.
|
||||
|
||||
More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/).
|
||||
|
@ -1,148 +0,0 @@
|
||||
# Adding custom mutators to AFL using Python modules
|
||||
|
||||
This file describes how you can utilize the external Python API to write
|
||||
your own custom mutation routines.
|
||||
|
||||
Note: This feature is highly experimental. Use at your own risk.
|
||||
|
||||
Implemented by Christian Holler (:decoder) <choller@mozilla.com>.
|
||||
|
||||
NOTE: Only cPython 2.7, 3.7 and above are supported, although others may work.
|
||||
Depending on with which version afl-fuzz was compiled against, you must use
|
||||
python2 or python3 syntax in your scripts!
|
||||
After a major version upgrade (e.g. 3.7 -> 3.8), a recompilation of afl-fuzz may be needed.
|
||||
|
||||
For an example and a template see ../examples/python_mutators/
|
||||
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
While AFLFuzz comes with a good selection of generic deterministic and
|
||||
non-deterministic mutation operations, it sometimes might make sense to extend
|
||||
these to implement strategies more specific to the target you are fuzzing.
|
||||
|
||||
For simplicity and in order to allow people without C knowledge to extend
|
||||
AFLFuzz, I implemented a "Python" stage that can make use of an external
|
||||
module (written in Python) that implements a custom mutation stage.
|
||||
|
||||
The main motivation behind this is to lower the barrier for people
|
||||
experimenting with this tool. Hopefully, someone will be able to do useful
|
||||
things with this extension.
|
||||
|
||||
If you find it useful, have questions or need additional features added to the
|
||||
interface, feel free to send a mail to <choller@mozilla.com>.
|
||||
|
||||
See the following information to get a better pictures:
|
||||
https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=930663
|
||||
|
||||
|
||||
## 2) How the Python module looks like
|
||||
|
||||
You can find a simple example in pymodules/example.py including documentation
|
||||
explaining each function. In the same directory, you can find another simple
|
||||
module that performs simple mutations.
|
||||
|
||||
Right now, "init" is called at program startup and can be used to perform any
|
||||
kinds of one-time initializations while "fuzz" is called each time a mutation
|
||||
is requested.
|
||||
|
||||
There is also optional support for a trimming API, see the section below for
|
||||
further information about this feature.
|
||||
|
||||
|
||||
## 3) How to compile AFLFuzz with Python support
|
||||
|
||||
You must install the python 3 or 2 development package of your Linux
|
||||
distribution before this will work. On Debian/Ubuntu/Kali this can be done
|
||||
with either:
|
||||
apt install python3-dev
|
||||
or
|
||||
apt install python-dev
|
||||
Note that for some distributions you might also need the package python[23]-apt
|
||||
|
||||
A prerequisite for using this mode is to compile AFLFuzz with Python support.
|
||||
|
||||
The AFL++ Makefile detects Python 3 and 2 through `python-config` if is is in the PATH
|
||||
and compiles afl-fuzz with the feature if available.
|
||||
|
||||
In case your setup is different set the necessary variables like this:
|
||||
PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make
|
||||
|
||||
|
||||
## 4) How to run AFLFuzz with your custom module
|
||||
|
||||
You must pass the module name inside the env variable AFL_PYTHON_MODULE.
|
||||
|
||||
In addition, if you are trying to load the module from the local directory,
|
||||
you must adjust your PYTHONPATH to reflect this circumstance. The following
|
||||
command should work if you are inside the aflfuzz directory:
|
||||
|
||||
$ AFL_PYTHON_MODULE="pymodules.test" PYTHONPATH=. ./afl-fuzz
|
||||
|
||||
Optionally, the following environment variables are supported:
|
||||
|
||||
AFL_PYTHON_ONLY - Disable all other mutation stages. This can prevent broken
|
||||
testcases (those that your Python module can't work with
|
||||
anymore) to fill up your queue. Best combined with a custom
|
||||
trimming routine (see below) because trimming can cause the
|
||||
same test breakage like havoc and splice.
|
||||
|
||||
AFL_DEBUG - When combined with AFL_NO_UI, this causes the C trimming code
|
||||
to emit additional messages about the performance and actions
|
||||
of your custom Python trimmer. Use this to see if it works :)
|
||||
|
||||
|
||||
## 5) Order and statistics
|
||||
|
||||
The Python stage is set to be the first non-deterministic stage (right before
|
||||
the havoc stage). In the statistics however, it shows up as the third number
|
||||
under "havoc". That's because I'm lazy and I didn't want to mess with the UI
|
||||
too much ;)
|
||||
|
||||
|
||||
## 6) Trimming support
|
||||
|
||||
The generic trimming routines implemented in AFLFuzz can easily destroy the
|
||||
structure of complex formats, possibly leading to a point where you have a lot
|
||||
of testcases in the queue that your Python module cannot process anymore but
|
||||
your target application still accepts. This is especially the case when your
|
||||
target can process a part of the input (causing coverage) and then errors out
|
||||
on the remaining input.
|
||||
|
||||
In such cases, it makes sense to implement a custom trimming routine in Python.
|
||||
The API consists of multiple methods because after each trimming step, we have
|
||||
to go back into the C code to check if the coverage bitmap is still the same
|
||||
for the trimmed input. Here's a quick API description:
|
||||
|
||||
init_trim: This method is called at the start of each trimming operation
|
||||
and receives the initial buffer. It should return the amount
|
||||
of iteration steps possible on this input (e.g. if your input
|
||||
has n elements and you want to remove them one by one, return n,
|
||||
if you do a binary search, return log(n), and so on...).
|
||||
|
||||
If your trimming algorithm doesn't allow you to determine the
|
||||
amount of (remaining) steps easily (esp. while running), then you
|
||||
can alternatively return 1 here and always return 0 in post_trim
|
||||
until you are finished and no steps remain. In that case,
|
||||
returning 1 in post_trim will end the trimming routine. The whole
|
||||
current index/max iterations stuff is only used to show progress.
|
||||
|
||||
trim: This method is called for each trimming operation. It doesn't
|
||||
have any arguments because we already have the initial buffer
|
||||
from init_trim and we can memorize the current state in global
|
||||
variables. This can also save reparsing steps for each iteration.
|
||||
It should return the trimmed input buffer, where the returned data
|
||||
must not exceed the initial input data in length. Returning anything
|
||||
that is larger than the original data (passed to init_trim) will
|
||||
result in a fatal abort of AFLFuzz.
|
||||
|
||||
post_trim: This method is called after each trim operation to inform you
|
||||
if your trimming step was successful or not (in terms of coverage).
|
||||
If you receive a failure here, you should reset your input to the
|
||||
last known good state.
|
||||
In any case, this method must return the next trim iteration index
|
||||
(from 0 to the maximum amount of steps you returned in init_trim).
|
||||
|
||||
Omitting any of the methods will cause Python trimming to be disabled and
|
||||
trigger a fallback to the builtin default trimming routine.
|
@ -1,7 +1,7 @@
|
||||
# Sister projects
|
||||
|
||||
This doc lists some of the projects that are inspired by, derived from,
|
||||
designed for, or meant to integrate with AFL. See README for the general
|
||||
designed for, or meant to integrate with AFL. See README.md for the general
|
||||
instruction manual.
|
||||
|
||||
!!!
|
||||
@ -252,7 +252,7 @@ https://code.google.com/p/address-sanitizer/wiki/AsanCoverage#Coverage_counters
|
||||
### AFL JS (Han Choongwoo)
|
||||
|
||||
One-off optimizations to speed up the fuzzing of JavaScriptCore (now likely
|
||||
superseded by LLVM deferred forkserver init - see llvm_mode/README.llvm).
|
||||
superseded by LLVM deferred forkserver init - see llvm_mode/README.md).
|
||||
|
||||
https://github.com/tunz/afl-fuzz-js
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Understanding the status screen
|
||||
|
||||
This document provides an overview of the status screen - plus tips for
|
||||
troubleshooting any warnings and red text shown in the UI. See README for
|
||||
troubleshooting any warnings and red text shown in the UI. See README.md for
|
||||
the general instruction manual.
|
||||
|
||||
## A note about colors
|
||||
@ -374,24 +374,38 @@ directory. This includes:
|
||||
|
||||
- `start_time` - unix time indicating the start time of afl-fuzz
|
||||
- `last_update` - unix time corresponding to the last update of this file
|
||||
- `run_time` - run time in seconds to the last update of this file
|
||||
- `fuzzer_pid` - PID of the fuzzer process
|
||||
- `cycles_done` - queue cycles completed so far
|
||||
- `cycles_wo_finds` - number of cycles without any new paths found
|
||||
- `execs_done` - number of execve() calls attempted
|
||||
- `execs_per_sec` - overall number of execs per second
|
||||
- `paths_total` - total number of entries in the queue
|
||||
- `paths_favored` - number of queue entries that are favored
|
||||
- `paths_found` - number of entries discovered through local fuzzing
|
||||
- `paths_imported` - number of entries imported from other instances
|
||||
- `max_depth` - number of levels in the generated data set
|
||||
- `cur_path` - currently processed entry number
|
||||
- `pending_favs` - number of favored entries still waiting to be fuzzed
|
||||
- `pending_total` - number of all entries waiting to be fuzzed
|
||||
- `stability - percentage of bitmap bytes that behave consistently
|
||||
- `variable_paths` - number of test cases showing variable behavior
|
||||
- `stability` - percentage of bitmap bytes that behave consistently
|
||||
- `bitmap_cvg` - percentage of edge coverage found in the map so far
|
||||
- `unique_crashes` - number of unique crashes recorded
|
||||
- `unique_hangs` - number of unique hangs encountered
|
||||
- `command_line` - full command line used for the fuzzing session
|
||||
- `slowest_exec_ms`- real time of the slowest execution in seconds
|
||||
- `last_path` - seconds since the last path was found
|
||||
- `last_crash` - seconds since the last crash was found
|
||||
- `last_hang` - seconds since the last hang was found
|
||||
- `execs_since_crash` - execs since the last crash was found
|
||||
- `exec_timeout` - the -t command line value
|
||||
- `slowest_exec_ms` - real time of the slowest execution in ms
|
||||
- `peak_rss_mb` - max rss usage reached during fuzzing in MB
|
||||
- `edges_found` - how many edges have been found
|
||||
- `var_byte_count` - how many edges are non-deterministic
|
||||
- `afl_banner` - banner text (e.g. the target name)
|
||||
- `afl_version` - the version of afl used
|
||||
- `target_mode` - default, persistent, qemu, unicorn, dumb
|
||||
- `command_line` - full command line used for the fuzzing session
|
||||
|
||||
Most of these map directly to the UI elements discussed earlier on.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Technical "whitepaper" for afl-fuzz
|
||||
|
||||
This document provides a quick overview of the guts of American Fuzzy Lop.
|
||||
See README for the general instruction manual; and for a discussion of
|
||||
See README.md for the general instruction manual; and for a discussion of
|
||||
motivations and design goals behind AFL, see historical_notes.md.
|
||||
|
||||
## 0. Design statement
|
||||
@ -286,8 +286,9 @@ operation of `afl-tmin` is as follows.
|
||||
|
||||
First, the tool automatically selects the operating mode. If the initial input
|
||||
crashes the target binary, afl-tmin will run in non-instrumented mode, simply
|
||||
keeping any tweaks that produce a simpler file but still crash the target. If
|
||||
the target is non-crashing, the tool uses an instrumented mode and keeps only
|
||||
keeping any tweaks that produce a simpler file but still crash the target.
|
||||
The same mode is used for hangs, if `-H` (hang mode) is specified.
|
||||
If the target is non-crashing, the tool uses an instrumented mode and keeps only
|
||||
the tweaks that produce exactly the same execution path.
|
||||
|
||||
The actual minimization algorithm is:
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
Here's a quick overview of the stuff you can find in this directory:
|
||||
|
||||
- custom_mutstors - An example custom mutator
|
||||
|
||||
- python_mutators - Python mutators examples
|
||||
- custom_mutators - example custom mutators in python an c
|
||||
|
||||
- argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed
|
||||
(e.g., to test setuid programs).
|
||||
|
@ -20,19 +20,24 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
CFLAGS = -fPIC -Wall -Wextra
|
||||
LDFLAGS = -shared
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
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
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
M32FLAG = -mbe32
|
||||
endif
|
||||
endif
|
||||
|
||||
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep gcc; echo $$?)
|
||||
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep arm; echo $$?)
|
||||
|
||||
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
|
||||
__M32FLAG=$(_M32FLAG:00=-mbe32)
|
||||
___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
|
||||
M32FLAG=$(___M32FLAG)
|
||||
|
||||
all: argvfuzz32.so argvfuzz64.so
|
||||
|
||||
|
7
examples/custom_mutators/Makefile
Normal file
7
examples/custom_mutators/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: libexamplemutator.so
|
||||
|
||||
libexamplemutator.so:
|
||||
$(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so
|
||||
|
||||
clean:
|
||||
rm -rf libexamplemutator.so
|
@ -1,2 +0,0 @@
|
||||
This is a simple example for the AFL_CUSTOM_MUTATOR_LIBRARY feature.
|
||||
For more information see [docs/custom_mutator.md](../docs/custom_mutator.md)
|
28
examples/custom_mutators/README.md
Normal file
28
examples/custom_mutators/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Examples for the custom mutator
|
||||
|
||||
These are example and helper files for the custom mutator feature.
|
||||
See [docs/custom_mutators.md](../docs/custom_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use python2.7 to compile python2 scripts!
|
||||
|
||||
example.c - this is a simple example written in C and should be compiled to a
|
||||
shared library. Use make to compile it and produce libexamplemutator.so
|
||||
|
||||
example.py - this is the template you can use, the functions are there but they
|
||||
are empty
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
||||
|
||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||
|
||||
XmlMutatorMin.py - module for XML mutation
|
||||
|
||||
custom_mutator_helpers.h is an header that defines some helper routines
|
||||
like surgical_havoc_mutate() that allow to perform a randomly chosen
|
||||
mutation from a subset of the havoc mutations.
|
||||
If you do so, you have to specify -I /path/to/AFLplusplus/include when
|
||||
compiling.
|
@ -7,6 +7,7 @@ from copy import deepcopy
|
||||
from lxml import etree as ET
|
||||
import random, re, io
|
||||
|
||||
|
||||
###########################
|
||||
# The XmlMutatorMin class #
|
||||
###########################
|
||||
@ -149,7 +150,7 @@ class XmlMutatorMin:
|
||||
|
||||
# We have the attribute to modify
|
||||
# Get its value
|
||||
attrib_value = rand_elem.get(rand_attrib);
|
||||
attrib_value = rand_elem.get(rand_attrib)
|
||||
# print("- Value: " + attrib_value)
|
||||
|
||||
# Should we work on the whole value?
|
@ -19,16 +19,19 @@ import random
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def randel(l):
|
||||
if not l:
|
||||
return None
|
||||
return l[random.randint(0, len(l)-1)]
|
||||
|
||||
|
||||
def randel_pop(l):
|
||||
if not l:
|
||||
return None
|
||||
return l.pop(random.randint(0, len(l)-1))
|
||||
|
||||
|
||||
def write_exc_example(data, exc):
|
||||
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
|
||||
|
342
examples/custom_mutators/custom_mutator_helpers.h
Normal file
342
examples/custom_mutators/custom_mutator_helpers.h
Normal file
@ -0,0 +1,342 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
#define RAND_BELOW(limit) (rand() % (limit))
|
||||
|
||||
/* 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
|
||||
|
||||
typedef struct {
|
||||
|
||||
} afl_t;
|
||||
|
||||
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
|
||||
|
||||
static s8 interesting_8[] = {INTERESTING_8};
|
||||
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
|
||||
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
|
||||
|
||||
switch (RAND_BELOW(12)) {
|
||||
|
||||
case 0: {
|
||||
|
||||
/* Flip a single bit somewhere. Spooky! */
|
||||
|
||||
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
|
||||
|
||||
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 1: {
|
||||
|
||||
/* Set byte to interesting value. */
|
||||
|
||||
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 2: {
|
||||
|
||||
/* Set word to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
|
||||
break;
|
||||
case 1:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 3: {
|
||||
|
||||
/* Set dword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 4: {
|
||||
|
||||
/* Set qword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 8) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 7) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u64 *)(out_buf + byte_idx) =
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u64 *)(out_buf + byte_idx) = SWAP64(
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 5: {
|
||||
|
||||
/* Randomly subtract from byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 6: {
|
||||
|
||||
/* Randomly add to byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 7: {
|
||||
|
||||
/* Randomly subtract from word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 8: {
|
||||
|
||||
/* Randomly add to word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 9: {
|
||||
|
||||
/* Randomly subtract from dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 10: {
|
||||
|
||||
/* Randomly add to dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 11: {
|
||||
|
||||
/* Just set a random byte to a random value. Because,
|
||||
why not. We use XOR with 1-255 to eliminate the
|
||||
possibility of a no-op. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This function calculates the next power of 2 greater or equal its argument.
|
||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
||||
*/
|
||||
static inline size_t next_pow2(size_t in) {
|
||||
|
||||
if (in == 0 || in > (size_t)-1)
|
||||
return 0; /* avoid undefined behaviour under-/overflow */
|
||||
size_t out = in - 1;
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
return out + 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(size_needed && *size >= size_needed)) return *buf;
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = realloc(*buf, next_size);
|
||||
*size = *buf ? next_size : 0;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
||||
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
|
||||
size_t *size2) {
|
||||
|
||||
void * scratch_buf = *buf1;
|
||||
size_t scratch_size = *size1;
|
||||
*buf1 = *buf2;
|
||||
*size1 = *size2;
|
||||
*buf2 = scratch_buf;
|
||||
*size2 = scratch_size;
|
||||
|
||||
}
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
375
examples/custom_mutators/example.c
Normal file
375
examples/custom_mutators/example.c
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
New Custom Mutator for AFL++
|
||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Shengtuo Hu <h1994st@gmail.com>
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
*/
|
||||
|
||||
// You need to use -I /path/to/AFLplusplus/include
|
||||
#include "custom_mutator_helpers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DATA_SIZE (100)
|
||||
|
||||
static const char *commands[] = {
|
||||
|
||||
"GET",
|
||||
"PUT",
|
||||
"DEL",
|
||||
|
||||
};
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_t *afl;
|
||||
|
||||
// any additional data here!
|
||||
size_t trim_size_current;
|
||||
int trimmming_steps;
|
||||
int cur_step;
|
||||
|
||||
// Reused buffers:
|
||||
BUF_VAR(u8, fuzz);
|
||||
BUF_VAR(u8, data);
|
||||
BUF_VAR(u8, havoc);
|
||||
BUF_VAR(u8, trim);
|
||||
BUF_VAR(u8, pre_save);
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
/**
|
||||
* Initialize this custom mutator
|
||||
*
|
||||
* @param[in] afl a pointer to the internal state object. Can be ignored for
|
||||
* now.
|
||||
* @param[in] seed A seed for this mutator - the same seed should always mutate
|
||||
* in the same way.
|
||||
* @return Pointer to the data object this custom mutator instance should use.
|
||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||
* Return NULL on error.
|
||||
*/
|
||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed); // needed also by surgical_havoc_mutate()
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
* (Optional for now. Required in the future)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to input data to be mutated
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
|
||||
* error.
|
||||
* @param[in] add_buf Buffer containing the additional test case
|
||||
* @param[in] add_buf_size Size of the additional test case
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must not
|
||||
* produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
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, // add_buf can be NULL
|
||||
size_t max_size) {
|
||||
|
||||
// Make sure that the packet size does not exceed the maximum size expected by
|
||||
// the fuzzer
|
||||
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
|
||||
|
||||
// maybe_grow is optimized to be quick for reused buffers.
|
||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
|
||||
if (!mutated_out) {
|
||||
|
||||
*out_buf = NULL;
|
||||
perror("custom mutator allocation (maybe_grow)");
|
||||
return 0; /* afl-fuzz will very likely error out after this. */
|
||||
|
||||
}
|
||||
|
||||
// Randomly select a command string to add as a header to the packet
|
||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||
|
||||
// Mutate the payload of the packet
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
|
||||
// Randomly perform one of the (no len modification) havoc mutations
|
||||
surgical_havoc_mutate(mutated_out, 3, mutated_size);
|
||||
|
||||
}
|
||||
|
||||
*out_buf = mutated_out;
|
||||
return mutated_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A post-processing function to use right before AFL writes the test case to
|
||||
* disk in order to execute the target.
|
||||
*
|
||||
* (Optional) If this functionality is not needed, simply don't define this
|
||||
* function.
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Buffer containing the test case to be executed
|
||||
* @param[in] buf_size Size of the test case
|
||||
* @param[out] out_buf Pointer to the buffer containing the test case after
|
||||
* processing. External library should allocate memory for out_buf.
|
||||
* The buf pointer may be reused (up to the given buf_size);
|
||||
* @return Size of the output buffer after processing or the needed amount.
|
||||
* A return of 0 indicates an error.
|
||||
*/
|
||||
size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
uint8_t **out_buf) {
|
||||
|
||||
uint8_t *pre_save_buf = maybe_grow(BUF_PARAMS(data, pre_save), buf_size + 5);
|
||||
if (!pre_save_buf) {
|
||||
|
||||
perror("custom mutator realloc failed.");
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
memcpy(pre_save_buf + 5, buf, buf_size);
|
||||
pre_save_buf[0] = 'A';
|
||||
pre_save_buf[1] = 'F';
|
||||
pre_save_buf[2] = 'L';
|
||||
pre_save_buf[3] = '+';
|
||||
pre_save_buf[4] = '+';
|
||||
|
||||
*out_buf = pre_save_buf;
|
||||
|
||||
return buf_size + 5;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called at the start of each trimming operation and receives
|
||||
* the initial buffer. It should return the amount of iteration steps possible
|
||||
* on this input (e.g. if your input has n elements and you want to remove
|
||||
* them one by one, return n, if you do a binary search, return log(n),
|
||||
* and so on...).
|
||||
*
|
||||
* If your trimming algorithm doesn't allow you to determine the amount of
|
||||
* (remaining) steps easily (esp. while running), then you can alternatively
|
||||
* return 1 here and always return 0 in post_trim until you are finished and
|
||||
* no steps remain. In that case, returning 1 in post_trim will end the
|
||||
* trimming routine. The whole current index/max iterations stuff is only used
|
||||
* to show progress.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param buf Buffer containing the test case
|
||||
* @param buf_size Size of the test case
|
||||
* @return The amount of possible iteration steps to trim the input.
|
||||
* negative on error.
|
||||
*/
|
||||
int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size) {
|
||||
|
||||
// We simply trim once
|
||||
data->trimmming_steps = 1;
|
||||
|
||||
data->cur_step = 0;
|
||||
|
||||
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
|
||||
|
||||
perror("init_trim grow");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
memcpy(data->trim_buf, buf, buf_size);
|
||||
|
||||
data->trim_size_current = buf_size;
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called for each trimming operation. It doesn't have any
|
||||
* arguments because we already have the initial buffer from init_trim and we
|
||||
* can memorize the current state in *data. This can also save
|
||||
* reparsing steps for each iteration. It should return the trimmed input
|
||||
* buffer, where the returned data must not exceed the initial input data in
|
||||
* length. Returning anything that is larger than the original data (passed
|
||||
* to init_trim) will result in a fatal abort of AFLFuzz.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[out] out_buf Pointer to the buffer containing the trimmed test case.
|
||||
* External library should allocate memory for out_buf.
|
||||
* AFL++ will not release the memory after saving the test case.
|
||||
* Keep a ref in *data.
|
||||
* *out_buf = NULL is treated as error.
|
||||
* @return Pointer to the size of the trimmed test case
|
||||
*/
|
||||
size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) {
|
||||
|
||||
*out_buf = data->trim_buf;
|
||||
|
||||
// Remove the last byte of the trimming input
|
||||
return data->trim_size_current - 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after each trim operation to inform you if your
|
||||
* trimming step was successful or not (in terms of coverage). If you receive
|
||||
* a failure here, you should reset your input to the last known good state.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param success Indicates if the last trim operation was successful.
|
||||
* @return The next trim iteration index (from 0 to the maximum amount of
|
||||
* steps returned in init_trim). negative ret on failure.
|
||||
*/
|
||||
int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
|
||||
|
||||
if (success) {
|
||||
|
||||
++data->cur_step;
|
||||
return data->cur_step;
|
||||
|
||||
}
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a single custom mutation on a given input.
|
||||
* This mutation is stacked with the other muatations in havoc.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to the input data to be mutated and the mutated
|
||||
* output
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf The output buffer. buf can be reused, if the content
|
||||
* fits. *out_buf = NULL is treated as error.
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must
|
||||
* not produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
|
||||
u8 **out_buf, size_t max_size) {
|
||||
|
||||
if (buf_size == 0) {
|
||||
|
||||
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
|
||||
if (!*out_buf) {
|
||||
|
||||
perror("custom havoc: maybe_grow");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
**out_buf = rand() % 256;
|
||||
buf_size = 1;
|
||||
|
||||
} else {
|
||||
|
||||
// We reuse buf here. It's legal and faster.
|
||||
*out_buf = buf;
|
||||
|
||||
}
|
||||
|
||||
size_t victim = rand() % buf_size;
|
||||
(*out_buf)[victim] += rand() % 10;
|
||||
|
||||
return buf_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability (in percentage) that afl_custom_havoc_mutation
|
||||
* is called in havoc. By default it is 6 %.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @return The probability (0-100).
|
||||
*/
|
||||
uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
|
||||
|
||||
return 5; // 5 %
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the fuzzer should fuzz the queue entry or not.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename File name of the test case in the queue entry
|
||||
* @return Return True(1) if the fuzzer will fuzz the queue entry, and
|
||||
* False(0) otherwise.
|
||||
*/
|
||||
uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for additional analysis (e.g. calling a different tool that does a
|
||||
* different kind of coverage and saves this for the custom mutator).
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename_new_queue File name of the new queue entry
|
||||
* @param filename_orig_queue File name of the original queue entry
|
||||
*/
|
||||
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
/* Additional analysis on the original or new test case */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->pre_save_buf);
|
||||
free(data->havoc_buf);
|
||||
free(data->data_buf);
|
||||
free(data->fuzz_buf);
|
||||
free(data->trim_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import random
|
||||
|
||||
|
||||
COMMANDS = [
|
||||
b"GET",
|
||||
b"PUT",
|
||||
b"DEL",
|
||||
]
|
||||
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
@ -24,9 +32,13 @@ def init(seed):
|
||||
@param seed: A 32-bit random value
|
||||
'''
|
||||
random.seed(seed)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
|
||||
def deinit():
|
||||
pass
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
'''
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@ -36,11 +48,16 @@ def fuzz(buf, add_buf):
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@type max_size: int
|
||||
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||
produce data larger than max_size.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
||||
ret = bytearray(buf)
|
||||
# Do something interesting with ret
|
||||
ret = bytearray(100)
|
||||
|
||||
ret[:3] = random.choice(COMMANDS)
|
||||
|
||||
return ret
|
||||
|
||||
@ -101,3 +118,68 @@ def fuzz(buf, add_buf):
|
||||
# # removed in the last step
|
||||
#
|
||||
# return next_index
|
||||
#
|
||||
# def pre_save(buf):
|
||||
# '''
|
||||
# Called just before the execution to write the test case in the format
|
||||
# expected by the target
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer containing the test case to be executed
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: The buffer containing the test case after
|
||||
# '''
|
||||
# return buf
|
||||
#
|
||||
# def havoc_mutation(buf, max_size):
|
||||
# '''
|
||||
# Perform a single custom mutation on a given input.
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer that should be mutated.
|
||||
#
|
||||
# @type max_size: int
|
||||
# @param max_size: Maximum size of the mutated output. The mutation must not
|
||||
# produce data larger than max_size.
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: A new bytearray containing the mutated data
|
||||
# '''
|
||||
# return mutated_buf
|
||||
#
|
||||
# def havoc_mutation_probability():
|
||||
# '''
|
||||
# Called for each `havoc_mutation`. Return the probability (in percentage)
|
||||
# that `havoc_mutation` is called in havoc. Be default it is 6%.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The probability (0-100)
|
||||
# '''
|
||||
# return prob
|
||||
#
|
||||
# def queue_get(filename):
|
||||
# '''
|
||||
# Called at the beginning of each fuzz iteration to determine whether the
|
||||
# test case should be fuzzed
|
||||
#
|
||||
# @type filename: str
|
||||
# @param filename: File name of the test case in the current queue entry
|
||||
#
|
||||
# @rtype: bool
|
||||
# @return: Return True if the custom mutator decides to fuzz the test case,
|
||||
# and False otherwise
|
||||
# '''
|
||||
# return True
|
||||
#
|
||||
# def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
# '''
|
||||
# Called after adding a new test case to the queue
|
||||
#
|
||||
# @type filename_new_queue: str
|
||||
# @param filename_new_queue: File name of the new queue entry
|
||||
#
|
||||
# @type filename_orig_queue: str
|
||||
# @param filename_orig_queue: File name of the original queue entry
|
||||
# '''
|
||||
# pass
|
@ -16,6 +16,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
@ -25,9 +26,9 @@ def init(seed):
|
||||
'''
|
||||
# Seed our RNG
|
||||
random.seed(seed)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
'''
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@ -37,6 +38,10 @@ def fuzz(buf, add_buf):
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@type max_size: int
|
||||
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||
produce data larger than max_size.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
'''
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
Simple Custom Mutator for AFL
|
||||
|
||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||
|
||||
This a simple mutator that assumes that the generates messages starting with
|
||||
one of the three strings GET, PUT, or DEL followed by a payload. The mutator
|
||||
randomly selects a commend and mutates the payload of the seed provided as
|
||||
input.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *commands[] = {
|
||||
|
||||
"GET",
|
||||
"PUT",
|
||||
"DEL",
|
||||
|
||||
};
|
||||
|
||||
static size_t data_size = 100;
|
||||
|
||||
size_t afl_custom_mutator(uint8_t *data, size_t size, uint8_t *mutated_out,
|
||||
size_t max_size, unsigned int seed) {
|
||||
|
||||
// Seed the PRNG
|
||||
srand(seed);
|
||||
|
||||
// Make sure that the packet size does not exceed the maximum size expected by
|
||||
// the fuzzer
|
||||
size_t mutated_size = data_size <= max_size ? data_size : max_size;
|
||||
|
||||
// Randomly select a command string to add as a header to the packet
|
||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||
|
||||
// Mutate the payload of the packet
|
||||
for (int i = 3; i < mutated_size; i++) {
|
||||
|
||||
mutated_out[i] = (data[i] + rand() % 10) & 0xff;
|
||||
|
||||
}
|
||||
|
||||
return mutated_size;
|
||||
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ __seed__ = "RANDOM"
|
||||
__log__ = False
|
||||
__log_file__ = "wrapper.log"
|
||||
|
||||
# AFL functions
|
||||
|
||||
# AFL functions
|
||||
def log(text):
|
||||
"""
|
||||
Logger
|
||||
@ -24,6 +24,7 @@ def log(text):
|
||||
with open(__log_file__, "a") as logf:
|
||||
logf.write("[%s] %s\n" % (__seed__, text))
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
@ -42,7 +43,8 @@ def init(seed):
|
||||
except RuntimeError as e:
|
||||
log("init(): Can't create mutator: %s" % e.message)
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
"""
|
||||
Called for each fuzzing iteration.
|
||||
"""
|
||||
@ -62,7 +64,7 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
buf_str = str(buf)
|
||||
log("fuzz(): AFL buffer converted to a string")
|
||||
except:
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't convert AFL buffer to a string")
|
||||
|
||||
@ -71,7 +73,7 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
__mutator__.init_from_string(buf_str)
|
||||
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
||||
except:
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||
|
||||
@ -84,7 +86,7 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
__mutator__.mutate(max=5)
|
||||
log("fuzz(): Input mutated")
|
||||
except:
|
||||
except Exception:
|
||||
log("fuzz(): Can't mutate input => returning buf")
|
||||
return buf
|
||||
|
||||
@ -92,7 +94,7 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
data = bytearray(__mutator__.save_to_string())
|
||||
log("fuzz(): Mutated data converted as bytes")
|
||||
except:
|
||||
except Exception:
|
||||
log("fuzz(): Can't convert mutated data to bytes => returning buf")
|
||||
return buf
|
||||
|
||||
@ -100,8 +102,8 @@ def fuzz(buf, add_buf):
|
||||
log("fuzz(): Returning %d bytes" % len(data))
|
||||
return data
|
||||
|
||||
# Main (for debug)
|
||||
|
||||
# Main (for debug)
|
||||
if __name__ == '__main__':
|
||||
|
||||
__log__ = True
|
||||
@ -114,4 +116,3 @@ if __name__ == '__main__':
|
||||
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
||||
out = fuzz(in_1, in_2)
|
||||
print(out)
|
||||
|
@ -3,6 +3,7 @@
|
||||
--------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
Edited by Dominik Maier, 2020
|
||||
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
@ -41,22 +42,23 @@
|
||||
AFL will call the afl_postprocess() function for every mutated output buffer.
|
||||
From there, you have three choices:
|
||||
|
||||
1) If you don't want to modify the test case, simply return the original
|
||||
buffer pointer ('in_buf').
|
||||
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
|
||||
and return the original `len`.
|
||||
|
||||
2) If you want to skip this test case altogether and have AFL generate a
|
||||
new one, return NULL. Use this sparingly - it's faster than running
|
||||
the target program with patently useless inputs, but still wastes CPU
|
||||
time.
|
||||
new one, return 0 or set `*out_buf = NULL`.
|
||||
Use this sparingly - it's faster than running the target program
|
||||
with patently useless inputs, but still wastes CPU time.
|
||||
|
||||
3) If you want to modify the test case, allocate an appropriately-sized
|
||||
buffer, move the data into that buffer, make the necessary changes, and
|
||||
then return the new pointer. You can update *len if necessary, too.
|
||||
then return the new pointer as out_buf. Return an appropriate len
|
||||
afterwards.
|
||||
|
||||
Note that the buffer will *not* be freed for you. To avoid memory leaks,
|
||||
you need to free it or reuse it on subsequent calls (as shown below).
|
||||
|
||||
*** DO NOT MODIFY THE ORIGINAL 'in_buf' BUFFER. ***
|
||||
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
|
||||
|
||||
Aight. The example below shows a simple postprocessor that tries to make
|
||||
sure that all input files start with "GIF89a".
|
||||
@ -74,47 +76,84 @@
|
||||
|
||||
#define HEADER "GIF89a"
|
||||
|
||||
typedef struct post_state {
|
||||
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
|
||||
} post_state_t;
|
||||
|
||||
void *afl_postprocess_init(void *afl) {
|
||||
|
||||
post_state_t *state = malloc(sizeof(post_state_t));
|
||||
if (!state) {
|
||||
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
||||
if (!state->buf) { return NULL; }
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
/* The actual postprocessor routine called by afl-fuzz: */
|
||||
|
||||
const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
unsigned int* len) {
|
||||
|
||||
static unsigned char* saved_buf;
|
||||
unsigned char* new_buf;
|
||||
size_t afl_postprocess(post_state_t *data, unsigned char *in_buf,
|
||||
unsigned int len, unsigned char **out_buf) {
|
||||
|
||||
/* Skip execution altogether for buffers shorter than 6 bytes (just to
|
||||
show how it's done). We can trust *len to be sane. */
|
||||
show how it's done). We can trust len to be sane. */
|
||||
|
||||
if (*len < strlen(HEADER)) return NULL;
|
||||
if (len < strlen(HEADER)) return 0;
|
||||
|
||||
/* Do nothing for buffers that already start with the expected header. */
|
||||
|
||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf;
|
||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate memory for new buffer, reusing previous allocation if
|
||||
possible. */
|
||||
|
||||
new_buf = realloc(saved_buf, *len);
|
||||
*out_buf = realloc(data->buf, len);
|
||||
|
||||
/* If we're out of memory, the most graceful thing to do is to return the
|
||||
original buffer and give up on modifying it. Let AFL handle OOM on its
|
||||
own later on. */
|
||||
|
||||
if (!new_buf) return in_buf;
|
||||
saved_buf = new_buf;
|
||||
if (!*out_buf) {
|
||||
|
||||
/* Copy the original data to the new location. */
|
||||
|
||||
memcpy(new_buf, in_buf, *len);
|
||||
|
||||
/* Insert the new header. */
|
||||
|
||||
memcpy(new_buf, HEADER, strlen(HEADER));
|
||||
|
||||
/* Return modified buffer. No need to update *len in this particular case,
|
||||
as we're not changing it. */
|
||||
|
||||
return new_buf;
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Copy the original data to the new location. */
|
||||
|
||||
memcpy(*out_buf, in_buf, len);
|
||||
|
||||
/* Insert the new header. */
|
||||
|
||||
memcpy(*out_buf, HEADER, strlen(HEADER));
|
||||
|
||||
/* Return the new len. It hasn't changed, so it's just len. */
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Gets called afterwards */
|
||||
void afl_postprocess_deinit(post_state_t *data) {
|
||||
|
||||
free(data->buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
Adapted to the new API, 2020 by Dominik Maier
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -35,11 +36,32 @@
|
||||
|
||||
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
|
||||
|
||||
const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
unsigned int* len) {
|
||||
typedef struct post_state {
|
||||
|
||||
static unsigned char* saved_buf;
|
||||
static unsigned int saved_len;
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
|
||||
} post_state_t;
|
||||
|
||||
void *afl_postprocess_init(void *afl) {
|
||||
|
||||
post_state_t *state = malloc(sizeof(post_state_t));
|
||||
if (!state) {
|
||||
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
||||
if (!state->buf) { return NULL; }
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
size_t afl_postprocess(post_state_t *data, const unsigned char *in_buf,
|
||||
unsigned int len, const unsigned char **out_buf) {
|
||||
|
||||
unsigned char *new_buf = (unsigned char *)in_buf;
|
||||
unsigned int pos = 8;
|
||||
@ -47,12 +69,17 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
/* Don't do anything if there's not enough room for the PNG header
|
||||
(8 bytes). */
|
||||
|
||||
if (*len < 8) return in_buf;
|
||||
if (len < 8) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
|
||||
don't have that, we can bail out. */
|
||||
|
||||
while (pos + 12 <= *len) {
|
||||
while (pos + 12 <= len) {
|
||||
|
||||
unsigned int chunk_len, real_cksum, file_cksum;
|
||||
|
||||
@ -62,7 +89,7 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
/* Bail out if chunk size is too big or goes past EOF. */
|
||||
|
||||
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > *len) break;
|
||||
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
|
||||
|
||||
/* Chunk checksum is calculated for chunk ID (dword) and the actual
|
||||
payload. */
|
||||
@ -82,17 +109,23 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
if (new_buf == in_buf) {
|
||||
|
||||
if (*len <= saved_len) {
|
||||
if (len <= data->size) {
|
||||
|
||||
new_buf = saved_buf;
|
||||
new_buf = data->buf;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = realloc(saved_buf, UP4K(*len));
|
||||
if (!new_buf) return in_buf;
|
||||
saved_buf = new_buf;
|
||||
saved_len = UP4K(*len);
|
||||
memcpy(new_buf, in_buf, *len);
|
||||
new_buf = realloc(data->buf, UP4K(len));
|
||||
if (!new_buf) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
data->buf = new_buf;
|
||||
data->size = UP4K(len);
|
||||
memcpy(new_buf, in_buf, len);
|
||||
|
||||
}
|
||||
|
||||
@ -108,7 +141,16 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
}
|
||||
|
||||
return new_buf;
|
||||
*out_buf = new_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Gets called afterwards */
|
||||
void afl_postprocess_deinit(post_state_t *data) {
|
||||
|
||||
free(data->buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
These are example and helper files for the AFL_PYTHON_MODULE feature.
|
||||
See [docs/python_mutators.md](../docs/python_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use pyton2.7 to compile python2 scripts!
|
||||
|
||||
|
||||
example.py - this is the template you can use, the functions are there
|
||||
but they are empty
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
||||
|
||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||
|
||||
XmlMutatorMin.py - module for XML mutation
|
@ -38,12 +38,13 @@ enum {
|
||||
void afl_persistent_hook(uint64_t *regs, uint64_t guest_base) {
|
||||
|
||||
// In this example the register RDI is pointing to the memory location
|
||||
// of the target buffer, and the length of the input is in RAX.
|
||||
// of the target buffer, and the length of the input is in RSI.
|
||||
// This can be seen with a debugger, e.g. gdb (and "disass main")
|
||||
|
||||
printf("reading into %p\n", regs[R_EDI]);
|
||||
size_t r = read(0, g2h(regs[R_EDI]), 1024);
|
||||
regs[R_EAX] = r;
|
||||
printf("readed %ld bytes\n", r);
|
||||
regs[R_ESI] = r;
|
||||
printf("read %ld bytes\n", r);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int target_func(char *buf, int size) {
|
||||
int target_func(unsigned char *buf, int size) {
|
||||
|
||||
printf("buffer:%p, size:%p\n", buf, size);
|
||||
switch (buf[0]) {
|
||||
|
@ -18,18 +18,29 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
CFLAGS = -fPIC -Wall -Wextra
|
||||
LDFLAGS = -shared
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
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
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
M32FLAG = -mbe32
|
||||
endif
|
||||
endif
|
||||
|
||||
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep gcc; echo $$?)
|
||||
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep 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: socketfuzz32.so socketfuzz64.so
|
||||
|
||||
|
160
gcc_plugin/GNUmakefile
Normal file
160
gcc_plugin/GNUmakefile
Normal file
@ -0,0 +1,160 @@
|
||||
#
|
||||
# american fuzzy lop++ - GCC plugin instrumentation
|
||||
# -----------------------------------------------
|
||||
#
|
||||
# Written by Austin Seipp <aseipp@pobox.com> and
|
||||
# Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski and
|
||||
# Heiko Eißfeldt <heiko@hexco.de>
|
||||
#
|
||||
# GCC integration design is based on the LLVM design, which comes
|
||||
# from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015 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
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS = -Wall -I../include -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS := $(CXXFLAGS) -Wall
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
ifeq "clang" "$(CC)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
ifeq "clang++" "$(CXX)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include"
|
||||
HASH=\#
|
||||
|
||||
GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCBINDIR = $(shell dirname `command -v $(CC)` 2>/dev/null )
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
|
||||
|
||||
|
||||
all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps
|
||||
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-gcc-fast ../afl-g++-fast
|
||||
|
||||
../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-gcc-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-gcc-fast.8 ../afl-g++-fast.8
|
||||
|
||||
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.whitelist.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.whitelist.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
@ -21,87 +21,105 @@
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops
|
||||
CFLAGS += -Wall -I../include -D_FORTIFY_SOURCE=2 -Wno-pointer-sign \
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
VERSION:sh= grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS = -Wall -I../include -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops
|
||||
CXXEFLAGS := $(CXXFLAGS) -Wall -D_FORTIFY_SOURCE=2
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS = $(CXXFLAGS) -Wall
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include"
|
||||
MYCC=$(CC:clang=gcc)
|
||||
MYCXX=$(CXX:clang++=g++)
|
||||
|
||||
PLUGIN_PATH = $(shell $(MYCC) -print-file-name=plugin)
|
||||
PLUGIN_PATH:sh= $(MYCC) -print-file-name=plugin
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(PLUGIN_PATH)/include"
|
||||
HASH=\#
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
GCCVER = $(shell $(MYCC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCBINDIR = $(shell dirname `command -v $(MYCC)` 2>/dev/null )
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
_SHMAT_OK= $(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )
|
||||
_SHMAT_OK:sh= echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2
|
||||
|
||||
IGNORE_MMAP=$(TEST_MMAP:1=0)
|
||||
__SHMAT_OK=$(_SHMAT_OK)$(IGNORE_MMAP)
|
||||
___SHMAT_OK=$(__SHMAT_OK:10=0)
|
||||
SHMAT_OK=$(___SHMAT_OK:1=1)
|
||||
_CFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
CFLAGS_ADD=$(_CFLAGS_ADD:0=-DUSEMMAP=1)
|
||||
|
||||
_LDFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt)
|
||||
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
|
||||
|
||||
|
||||
all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
debug:
|
||||
@echo _SHMAT_OK = $(_SHMAT_OK)
|
||||
@echo IGNORE_MMAP = $(IGNORE_MMAP)
|
||||
@echo __SHMAT_OK = $(__SHMAT_OK)
|
||||
@echo ___SHMAT_OK = $(___SHMAT_OK)
|
||||
@echo SHMAT_OK = $(SHMAT_OK)
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
@if [ "$(SHMAT_OK)" == "1" ]; then \
|
||||
echo "[+] shmat seems to be working."; \
|
||||
rm -f .test2; \
|
||||
else \
|
||||
echo "[-] shmat seems not to be working, switching to mmap implementation"; \
|
||||
fi
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for working '$(MYCC)'..."
|
||||
@type $(MYCC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(MYCC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
# @$(MYCC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@test -d `$(MYCC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
$(MYCC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps
|
||||
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
$(MYCC) -DAFL_GCC_CC=\"$(MYCC)\" -DAFL_GCC_CXX=\"$(MYCXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-gcc-fast ../afl-g++-fast
|
||||
|
||||
../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
$(MYCXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
$(MYCC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@ -109,7 +127,7 @@ all_done: test_build
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
VPATH = ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@ -123,13 +141,19 @@ vpath % ..
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-gcc-fast.8 ../afl-g++-fast.8
|
||||
|
||||
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.whitelist.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.whitelist.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
||||
|
@ -323,14 +323,30 @@ int main(int argc, char** argv, char** envp) {
|
||||
"programs\n"
|
||||
"(similarly to the LLVM plugin used by afl-clang-fast).\n\n"
|
||||
|
||||
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
|
||||
"Setting\n"
|
||||
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
|
||||
BIN_PATH, BIN_PATH);
|
||||
"Environment variables used:\n"
|
||||
"AFL_CC: path to the C compiler to use\n"
|
||||
"AFL_CXX: path to the C++ compiler to use\n"
|
||||
"AFL_PATH: path to instrumenting pass and runtime (afl-gcc-rt.*o)\n"
|
||||
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_INST_RATIO: percentage of branches to instrument\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_DEBUG: enable developer debugging output\n"
|
||||
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_MSAN: activate memory sanitizer\n"
|
||||
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
|
||||
"AFL_GCC_WHITELIST: enable whitelisting (selective instrumentation)\n"
|
||||
|
||||
"\nafl-gcc-fast was built for gcc %s with the gcc binary path of "
|
||||
"\"%s\".\n\n",
|
||||
BIN_PATH, BIN_PATH, GCC_VERSION, GCC_BINDIR);
|
||||
|
||||
exit(1);
|
||||
|
||||
} else if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
} else if ((isatty(2) && !getenv("AFL_QUIET")) ||
|
||||
|
||||
getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-gcc-fast" VERSION cRST
|
||||
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n");
|
||||
@ -344,7 +360,9 @@ int main(int argc, char** argv, char** envp) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
check_environment_vars(envp);
|
||||
|
||||
|
@ -52,8 +52,8 @@
|
||||
#include "../config.h"
|
||||
#include "../include/debug.h"
|
||||
|
||||
/* clear helper AFL types pulls in, which intervene with gcc-plugin geaders from
|
||||
* GCC-8 */
|
||||
/* clear helper macros AFL types pull in, which intervene with gcc-plugin
|
||||
* headers from GCC-8 */
|
||||
#ifdef likely
|
||||
#undef likely
|
||||
#endif
|
||||
@ -533,7 +533,7 @@ int plugin_init(struct plugin_name_args * plugin_info,
|
||||
}
|
||||
|
||||
/* Show a banner */
|
||||
if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(G_(cCYA "afl-gcc-pass" VERSION cRST
|
||||
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n"));
|
||||
@ -567,7 +567,7 @@ int plugin_init(struct plugin_name_args * plugin_info,
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instWhiteListFilename);
|
||||
if (!fileStream) fatal_error(0, "Unable to open AFL_GCC_WHITELIST");
|
||||
if (!fileStream) PFATAL("Unable to open AFL_GCC_WHITELIST");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "../config.h"
|
||||
#include "../types.h"
|
||||
|
||||
#ifdef USEMMAP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
@ -48,8 +51,10 @@ u8 *__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_prev_loc;
|
||||
u32 __afl_final_loc;
|
||||
#else
|
||||
__thread u32 __afl_prev_loc;
|
||||
__thread u32 __afl_final_loc;
|
||||
#endif
|
||||
|
||||
/* Trace a basic block with some ID */
|
||||
@ -92,7 +97,7 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
printf("shm_open() failed\n");
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -104,7 +109,7 @@ static void __afl_map_shm(void) {
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
printf("mmap() failed\n");
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -214,7 +219,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
/* A simplified persistent mode handler, used as explained in README.llvm. */
|
||||
/* A simplified persistent mode handler, used as explained in README.md. */
|
||||
|
||||
int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -261,6 +262,7 @@ static const u8* main_payload_32 =
|
||||
" je __afl_setup_abort\n"
|
||||
"\n"
|
||||
#endif
|
||||
" movb $1, (%eax)\n"
|
||||
" /* Store the address of the SHM region. */\n"
|
||||
"\n"
|
||||
" movl %eax, __afl_area_ptr\n"
|
||||
@ -383,6 +385,7 @@ static const u8* main_payload_32 =
|
||||
#ifndef COVERAGE_ONLY
|
||||
" .comm __afl_prev_loc, 4, 32\n"
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
" .comm __afl_final_loc, 4, 32\n"
|
||||
" .comm __afl_fork_pid, 4, 32\n"
|
||||
" .comm __afl_temp, 4, 32\n"
|
||||
"\n"
|
||||
@ -563,6 +566,7 @@ static const u8* main_payload_64 =
|
||||
" je __afl_setup_abort\n"
|
||||
"\n"
|
||||
#endif
|
||||
" movb $1, (%rax)\n"
|
||||
" /* Store the address of the SHM region. */\n"
|
||||
"\n"
|
||||
" movq %rax, %rdx\n"
|
||||
|
1008
include/afl-fuzz.h
1008
include/afl-fuzz.h
File diff suppressed because it is too large
Load Diff
142
include/afl-prealloc.h
Normal file
142
include/afl-prealloc.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
american fuzzy lop++ - prealloc a buffer to reuse small elements often
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 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
|
||||
|
||||
*/
|
||||
|
||||
/* If we know we'll reuse small elements often, we'll just preallocate a buffer,
|
||||
* then fall back to malloc */
|
||||
// TODO: Replace free status check with bitmask+CLZ
|
||||
|
||||
#ifndef AFL_PREALLOC_H
|
||||
#define AFL_PREALLOC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
typedef enum prealloc_status {
|
||||
|
||||
PRE_STATUS_UNUSED = 0, /* free in buf */
|
||||
PRE_STATUS_USED, /* used in buf */
|
||||
PRE_STATUS_MALLOC /* system malloc */
|
||||
|
||||
} pre_status_t;
|
||||
|
||||
/* Adds the entry used for prealloc bookkeeping to this struct */
|
||||
|
||||
/* prealloc status of this instance */
|
||||
#define PREALLOCABLE pre_status_t pre_status
|
||||
|
||||
/* allocate an element of type *el_ptr, to this variable.
|
||||
Uses (and reuses) the given prealloc_buf before hitting libc's malloc.
|
||||
prealloc_buf must be the pointer to an array with type `type`.
|
||||
`type` must be a struct with uses PREALLOCABLE (a pre_status_t pre_status
|
||||
member). prealloc_size must be the array size. prealloc_counter must be a
|
||||
variable initialized with 0 (of any name).
|
||||
*/
|
||||
|
||||
#define PRE_ALLOC(el_ptr, prealloc_buf, prealloc_size, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
if ((prealloc_counter) >= (prealloc_size)) { \
|
||||
\
|
||||
el_ptr = malloc(sizeof(*el_ptr)); \
|
||||
el_ptr->pre_status = PRE_STATUS_MALLOC; \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
/* Find one of our preallocated elements */ \
|
||||
u32 i; \
|
||||
for (i = 0; i < (prealloc_size); i++) { \
|
||||
\
|
||||
el_ptr = &((prealloc_buf)[i]); \
|
||||
if (el_ptr->pre_status == PRE_STATUS_UNUSED) { \
|
||||
\
|
||||
(prealloc_counter)++; \
|
||||
el_ptr->pre_status = PRE_STATUS_USED; \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
if (!el_ptr) { FATAL("BUG in list.h -> no element found or allocated!"); } \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* Take a chosen (free) element from the prealloc_buf directly */
|
||||
|
||||
#define PRE_ALLOC_FORCE(el_ptr, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
if ((el_ptr)->pre_status != PRE_STATUS_UNUSED) { \
|
||||
\
|
||||
FATAL("PRE_ALLOC_FORCE element already allocated"); \
|
||||
\
|
||||
} \
|
||||
(el_ptr)->pre_status = PRE_STATUS_USED; \
|
||||
(prealloc_counter)++; \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* free an preallocated element */
|
||||
|
||||
#define PRE_FREE(el_ptr, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
switch ((el_ptr)->pre_status) { \
|
||||
\
|
||||
case PRE_STATUS_USED: { \
|
||||
\
|
||||
(el_ptr)->pre_status = PRE_STATUS_UNUSED; \
|
||||
(prealloc_counter)--; \
|
||||
if ((prealloc_counter) < 0) { \
|
||||
\
|
||||
FATAL("Inconsistent data in PRE_FREE"); \
|
||||
\
|
||||
} \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
case PRE_STATUS_MALLOC: { \
|
||||
\
|
||||
(el_ptr)->pre_status = PRE_STATUS_UNUSED; \
|
||||
DFL_ck_free((el_ptr)); \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
default: { \
|
||||
\
|
||||
FATAL("Double Free Detected"); \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
#endif
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -34,6 +35,14 @@
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Initial size used for ck_maybe_grow */
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
|
||||
|
||||
#ifndef _WANT_ORIGINAL_AFL_ALLOC
|
||||
// afl++ stuff without memory corruption checks - for speed
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
#define alloc_printf(_str...) \
|
||||
@ -101,10 +110,13 @@ static inline void* DFL_ck_alloc(u32 size) {
|
||||
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
||||
is set, the old memory will be also clobbered with 0xFF. */
|
||||
|
||||
static inline void DFL_ck_free(void *mem) {
|
||||
|
||||
if (!mem) return;
|
||||
|
||||
free(mem);
|
||||
|
||||
}
|
||||
@ -116,7 +128,6 @@ static inline void DFL_ck_free(void* mem) {
|
||||
static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
u8 *ret;
|
||||
u32 old_size = 0;
|
||||
|
||||
if (!size) {
|
||||
|
||||
@ -127,10 +138,12 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
|
||||
ret = realloc(orig, size);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
/* Catch pointer issues sooner: force relocation and make sure that the
|
||||
original buffer is wiped. */
|
||||
|
||||
if (size > old_size) memset(ret + old_size, 0, size - old_size);
|
||||
ret = realloc(orig, size);
|
||||
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
return (void *)ret;
|
||||
|
||||
@ -141,8 +154,6 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
|
||||
|
||||
if (orig) size += ALLOC_BLK_INC;
|
||||
|
||||
return DFL_ck_realloc(orig, size);
|
||||
|
||||
}
|
||||
@ -217,5 +228,638 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
|
||||
#define alloc_report()
|
||||
|
||||
#else
|
||||
// This is the original alloc-inl of stock afl
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
#define alloc_printf(_str...) \
|
||||
({ \
|
||||
\
|
||||
u8 *_tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char *)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
|
||||
#define ALLOC_CHECK_SIZE(_s) \
|
||||
do { \
|
||||
\
|
||||
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) \
|
||||
do { \
|
||||
\
|
||||
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Magic tokens used to mark used / freed chunks. */
|
||||
|
||||
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
|
||||
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
|
||||
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
|
||||
|
||||
/* Positions of guard tokens in relation to the user-visible pointer. */
|
||||
|
||||
#define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
|
||||
#define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
|
||||
#define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
|
||||
|
||||
#define ALLOC_OFF_HEAD 8
|
||||
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
|
||||
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
|
||||
#define ALLOC_BLK_INC 256
|
||||
|
||||
/* Sanity-checking macros for pointers. */
|
||||
|
||||
#define CHECK_PTR(_p) \
|
||||
do { \
|
||||
\
|
||||
if (_p) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
|
||||
ABORT("Use after free."); \
|
||||
else \
|
||||
ABORT("Corrupted head alloc canary."); \
|
||||
\
|
||||
} \
|
||||
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
|
||||
ABORT("Corrupted tail alloc canary."); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PTR_EXPR(_p) \
|
||||
({ \
|
||||
\
|
||||
typeof(_p) _tmp = (_p); \
|
||||
CHECK_PTR(_tmp); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
|
||||
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
|
||||
requests. */
|
||||
|
||||
static inline void *DFL_ck_alloc_nozero(u32 size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (!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 ret;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate a buffer, returning zeroed memory. */
|
||||
|
||||
static inline void *DFL_ck_alloc(u32 size) {
|
||||
|
||||
void *mem;
|
||||
|
||||
if (!size) return NULL;
|
||||
mem = DFL_ck_alloc_nozero(size);
|
||||
|
||||
return memset(mem, 0, size);
|
||||
|
||||
}
|
||||
|
||||
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
||||
is set, the old memory will be also clobbered with 0xFF. */
|
||||
|
||||
static inline void DFL_ck_free(void *mem) {
|
||||
|
||||
if (!mem) return;
|
||||
|
||||
CHECK_PTR(mem);
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
|
||||
/* Catch pointer issues sooner. */
|
||||
memset(mem, 0xFF, ALLOC_S(mem));
|
||||
|
||||
#endif /* DEBUG_BUILD */
|
||||
|
||||
ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
||||
|
||||
free(mem - ALLOC_OFF_HEAD);
|
||||
|
||||
}
|
||||
|
||||
/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
|
||||
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
|
||||
old memory is clobbered with 0xFF. */
|
||||
|
||||
static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
void *ret;
|
||||
u32 old_size = 0;
|
||||
|
||||
if (!size) {
|
||||
|
||||
DFL_ck_free(orig);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if (orig) {
|
||||
|
||||
CHECK_PTR(orig);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
ALLOC_C1(orig) = ALLOC_MAGIC_F;
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
old_size = ALLOC_S(orig);
|
||||
orig -= ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_CHECK_SIZE(old_size);
|
||||
|
||||
}
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
#else
|
||||
|
||||
/* Catch pointer issues sooner: force relocation and make sure that the
|
||||
original buffer is wiped. */
|
||||
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
if (orig) {
|
||||
|
||||
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
|
||||
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
||||
|
||||
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
|
||||
|
||||
free(orig);
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
if (size > old_size) memset(ret + old_size, 0, size - old_size);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
|
||||
repeated small reallocs without complicating the user code). */
|
||||
|
||||
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
if (orig) {
|
||||
|
||||
CHECK_PTR(orig);
|
||||
|
||||
if (ALLOC_S(orig) >= size) return orig;
|
||||
|
||||
size += ALLOC_BLK_INC;
|
||||
|
||||
}
|
||||
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
return DFL_ck_realloc(orig, size);
|
||||
|
||||
}
|
||||
|
||||
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
|
||||
|
||||
static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
void *ret;
|
||||
u32 size;
|
||||
|
||||
if (!str) return NULL;
|
||||
|
||||
size = strlen((char *)str) + 1;
|
||||
|
||||
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, 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
|
||||
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above functions
|
||||
to user-visible names such as ck_alloc(). */
|
||||
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
|
||||
#else
|
||||
|
||||
/* In debugging mode, we also track allocations to detect memory leaks, and the
|
||||
flow goes through one more layer of indirection. */
|
||||
|
||||
/* Alloc tracking data structures: */
|
||||
|
||||
#define ALLOC_BUCKETS 4096
|
||||
|
||||
struct TRK_obj {
|
||||
|
||||
void *ptr;
|
||||
char *file, *func;
|
||||
u32 line;
|
||||
|
||||
};
|
||||
|
||||
#ifdef AFL_MAIN
|
||||
|
||||
struct TRK_obj *TRK[ALLOC_BUCKETS];
|
||||
u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
#define alloc_report() TRK_report()
|
||||
|
||||
#else
|
||||
|
||||
extern struct TRK_obj *TRK[ALLOC_BUCKETS];
|
||||
extern u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
#define alloc_report()
|
||||
|
||||
#endif /* ^AFL_MAIN */
|
||||
|
||||
/* Bucket-assigning function for a given pointer: */
|
||||
|
||||
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
|
||||
|
||||
/* Add a new entry to the list of allocated objects. */
|
||||
|
||||
static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
if (!ptr) return;
|
||||
|
||||
bucket = TRKH(ptr);
|
||||
|
||||
/* Find a free slot in the list of entries for that bucket. */
|
||||
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
|
||||
if (!TRK[bucket][i].ptr) {
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char *)file;
|
||||
TRK[bucket][i].func = (char *)func;
|
||||
TRK[bucket][i].line = line;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* No space available - allocate more. */
|
||||
|
||||
TRK[bucket] = DFL_ck_realloc_block(
|
||||
TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char *)file;
|
||||
TRK[bucket][i].func = (char *)func;
|
||||
TRK[bucket][i].line = line;
|
||||
|
||||
TRK_cnt[bucket]++;
|
||||
|
||||
}
|
||||
|
||||
/* Remove entry from the list of allocated objects. */
|
||||
|
||||
static inline void TRK_free_buf(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
if (!ptr) return;
|
||||
|
||||
bucket = TRKH(ptr);
|
||||
|
||||
/* Find the element on the list... */
|
||||
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
|
||||
if (TRK[bucket][i].ptr == ptr) {
|
||||
|
||||
TRK[bucket][i].ptr = 0;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", func, file,
|
||||
line);
|
||||
|
||||
}
|
||||
|
||||
/* Do a final report on all non-deallocated objects. */
|
||||
|
||||
static inline void TRK_report(void) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
fflush(0);
|
||||
|
||||
for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
if (TRK[bucket][i].ptr)
|
||||
WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
|
||||
TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
|
||||
|
||||
}
|
||||
|
||||
/* Simple wrappers for non-debugging functions: */
|
||||
|
||||
static inline void *TRK_ck_alloc(u32 size, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
void *ret = DFL_ck_alloc(size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void *ret = DFL_ck_realloc(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void *TRK_ck_realloc_block(void *orig, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void *ret = DFL_ck_realloc_block(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
void *ret = DFL_ck_strdup(str);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
TRK_free_buf(ptr, file, func, line);
|
||||
DFL_ck_free(ptr);
|
||||
|
||||
}
|
||||
|
||||
/* Aliasing user-facing names to tracking functions: */
|
||||
|
||||
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_alloc_nozero(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc(_p1, _p2) \
|
||||
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc_block(_p1, _p2) \
|
||||
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_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 */
|
||||
|
||||
#endif /* _WANT_ORIGINAL_AFL_ALLOC */
|
||||
|
||||
/* This function calculates the next power of 2 greater or equal its argument.
|
||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
||||
*/
|
||||
static inline size_t next_pow2(size_t in) {
|
||||
|
||||
if (in == 0 || in > (size_t)-1)
|
||||
return 0; /* avoid undefined behaviour under-/overflow */
|
||||
size_t out = in - 1;
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
return out + 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(size_needed && *size >= size_needed)) return *buf;
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow and zero size_needed */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = realloc(*buf, next_size);
|
||||
*size = *buf ? next_size : 0;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will FATAL if size_needed is <1.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *ck_maybe_grow(void **buf, size_t *size,
|
||||
size_t size_needed) {
|
||||
|
||||
/* Oops. found a bug? */
|
||||
if (unlikely(size_needed < 1)) FATAL("cannot grow to non-positive size");
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(*size >= size_needed)) return *buf;
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = ck_realloc(*buf, next_size);
|
||||
*size = next_size;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
||||
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
|
||||
size_t *size2) {
|
||||
|
||||
void * scratch_buf = *buf1;
|
||||
size_t scratch_size = *size1;
|
||||
*buf1 = *buf2;
|
||||
*size1 = *size2;
|
||||
*buf2 = scratch_buf;
|
||||
*size2 = scratch_size;
|
||||
|
||||
}
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif /* ! _HAVE_ALLOC_INL_H */
|
||||
|
||||
|
5
include/android-ashmem.h
Executable file → Normal file
5
include/android-ashmem.h
Executable file → Normal file
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
@ -6,9 +6,10 @@
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -25,14 +26,82 @@
|
||||
|
||||
#ifndef __AFLCOMMON_H
|
||||
#define __AFLCOMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "types.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
extern u8* target_path; /* Path to target binary */
|
||||
/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
|
||||
|
||||
void detect_file_args(char** argv, u8* prog_in);
|
||||
#define STRINGIFY_VAL_SIZE_MAX (16)
|
||||
|
||||
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin);
|
||||
void check_environment_vars(char **env);
|
||||
|
||||
char** get_qemu_argv(u8* own_loc, char** argv, int argc);
|
||||
char** get_wine_argv(u8* own_loc, char** argv, int argc);
|
||||
char **argv_cpy_dup(int argc, char **argv);
|
||||
void argv_cpy_free(char **argv);
|
||||
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char * get_afl_env(char *env);
|
||||
|
||||
extern u8 be_quiet;
|
||||
extern u8 *doc_path; /* path to documentation dir */
|
||||
|
||||
/* Get unix time in milliseconds */
|
||||
|
||||
u64 get_cur_time(void);
|
||||
|
||||
/* Get unix time in microseconds */
|
||||
|
||||
u64 get_cur_time_us(void);
|
||||
|
||||
/* Describe integer. The buf should be
|
||||
at least 6 bytes to fit all ints we randomly see.
|
||||
Will return buf for convenience. */
|
||||
|
||||
u8 *stringify_int(u8 *buf, size_t len, u64 val);
|
||||
|
||||
/* Describe float. Similar as int. */
|
||||
|
||||
u8 *stringify_float(u8 *buf, size_t len, double val);
|
||||
|
||||
/* Describe integer as memory size. */
|
||||
|
||||
u8 *stringify_mem_size(u8 *buf, size_t len, u64 val);
|
||||
|
||||
/* Describe time delta as string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Unsafe Describe integer. The buf sizes are not checked.
|
||||
This is unsafe but fast.
|
||||
Will return buf for convenience. */
|
||||
|
||||
u8 *u_stringify_int(u8 *buf, u64 val);
|
||||
|
||||
/* Unsafe describe float. Similar as unsafe int. */
|
||||
|
||||
u8 *u_stringify_float(u8 *buf, double val);
|
||||
|
||||
/* Unsafe describe integer as memory size. */
|
||||
|
||||
u8 *u_stringify_mem_size(u8 *buf, u64 val);
|
||||
|
||||
/* Unsafe describe time delta as string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Wrapper for select() and read(), reading exactly len bytes.
|
||||
Returns the time passed to read.
|
||||
If the wait times out, returns timeout_ms + 1;
|
||||
Returns 0 if an error occurred (fd closed, signal, ...); */
|
||||
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,7 +28,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++2.61c"
|
||||
#define VERSION "++2.63c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -40,6 +41,11 @@
|
||||
|
||||
#define USE_COLOR
|
||||
|
||||
/* If you want to have the original afl internal memory corruption checks.
|
||||
Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */
|
||||
|
||||
//#define _WANT_ORIGINAL_AFL_ALLOC
|
||||
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -31,6 +32,10 @@
|
||||
* Terminal colors *
|
||||
*******************/
|
||||
|
||||
#ifndef MESSAGES_TO_STDOUT
|
||||
#define MESSAGES_TO_STDOUT
|
||||
#endif
|
||||
|
||||
#ifdef USE_COLOR
|
||||
|
||||
#define cBLK "\x1b[0;30m"
|
||||
|
@ -1,97 +1,3 @@
|
||||
const char *afl_environment_variables[] = {
|
||||
|
||||
"AFL_ALIGNED_ALLOC",
|
||||
"AFL_ALLOW_TMP",
|
||||
"AFL_ANALYZE_HEX",
|
||||
"AFL_AS",
|
||||
"AFL_AS_FORCE_INSTRUMENT",
|
||||
"AFL_BENCH_JUST_ONE",
|
||||
"AFL_BENCH_UNTIL_CRASH",
|
||||
"AFL_CAL_FAST",
|
||||
"AFL_CC",
|
||||
"AFL_CMIN_ALLOW_ANY",
|
||||
"AFL_CMIN_CRASHES_ONLY",
|
||||
"AFL_CODE_END",
|
||||
"AFL_CODE_START",
|
||||
"AFL_COMPCOV_BINNAME",
|
||||
"AFL_COMPCOV_LEVEL",
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"AFL_CXX",
|
||||
"AFL_DEBUG",
|
||||
"AFL_DEBUG_CHILD_OUTPUT",
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_DISABLE_TRIM",
|
||||
"AFL_DONT_OPTIMIZE",
|
||||
"AFL_DUMB_FORKSRV",
|
||||
"AFL_ENTRYPOINT",
|
||||
"AFL_EXIT_WHEN_DONE",
|
||||
"AFL_FAST_CAL",
|
||||
"AFL_FORCE_UI",
|
||||
"AFL_GCC_WHITELIST",
|
||||
"AFL_GCJ",
|
||||
"AFL_HANG_TMOUT",
|
||||
"AFL_HARDEN",
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
||||
"AFL_IMPORT_FIRST",
|
||||
"AFL_INST_LIBS",
|
||||
"AFL_INST_RATIO",
|
||||
"AFL_KEEP_TRACES",
|
||||
"AFL_KEEP_ASSEMBLY",
|
||||
"AFL_LD_HARD_FAIL",
|
||||
"AFL_LD_LIMIT_MB",
|
||||
"AFL_LD_NO_CALLOC_OVER",
|
||||
"AFL_LD_PRELOAD",
|
||||
"AFL_LD_VERBOSE",
|
||||
"AFL_LLVM_CMPLOG",
|
||||
"AFL_LLVM_INSTRIM",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES",
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
|
||||
"AFL_LLVM_LAF_SPLIT_FLOATS",
|
||||
"AFL_LLVM_LAF_SPLIT_SWITCHES",
|
||||
"AFL_LLVM_LAF_TRANSFORM_COMPARES",
|
||||
"AFL_LLVM_NOT_ZERO",
|
||||
"AFL_LLVM_WHITELIST",
|
||||
"AFL_NO_AFFINITY",
|
||||
"AFL_NO_ARITH",
|
||||
"AFL_NO_BUILTIN",
|
||||
"AFL_NO_CPU_RED",
|
||||
"AFL_NO_FORKSRV",
|
||||
"AFL_NO_UI",
|
||||
"AFL_NO_X86", // not really an env but we dont want to warn on it
|
||||
"AFL_PATH",
|
||||
"AFL_PERFORMANCE_FILE",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PRELOAD",
|
||||
"AFL_PYTHON_MODULE",
|
||||
"AFL_PYTHON_ONLY",
|
||||
"AFL_QEMU_COMPCOV",
|
||||
"AFL_QEMU_COMPCOV_DEBUG",
|
||||
"AFL_QEMU_DEBUG_MAPS",
|
||||
"AFL_QEMU_DISABLE_CACHE",
|
||||
"AFL_QEMU_PERSISTENT_ADDR",
|
||||
"AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR",
|
||||
"AFL_QEMU_PERSISTENT_HOOK",
|
||||
"AFL_QEMU_PERSISTENT_RET",
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
|
||||
"AFL_QUIET",
|
||||
"AFL_RANDOM_ALLOC_CANARY",
|
||||
"AFL_REAL_PATH",
|
||||
"AFL_SHUFFLE_QUEUE",
|
||||
"AFL_SKIP_BIN_CHECK",
|
||||
"AFL_SKIP_CPUFREQ",
|
||||
"AFL_SKIP_CRASHES",
|
||||
"AFL_TMIN_EXACT",
|
||||
"AFL_TMPDIR",
|
||||
"AFL_TOKEN_FILE",
|
||||
"AFL_TRACE_PC",
|
||||
"AFL_USE_ASAN",
|
||||
"AFL_USE_MSAN",
|
||||
"AFL_USE_TRACE_PC",
|
||||
"AFL_USE_UBSAN",
|
||||
"AFL_WINE_PATH",
|
||||
NULL};
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -7,8 +7,9 @@
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,8 +28,48 @@
|
||||
#ifndef __AFL_FORKSERVER_H
|
||||
#define __AFL_FORKSERVER_H
|
||||
|
||||
void handle_timeout(int sig);
|
||||
void init_forkserver(char **argv);
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct afl_forkserver {
|
||||
|
||||
/* a program that includes afl-forkserver needs to define these */
|
||||
|
||||
u8 uses_asan; /* Target uses ASAN? */
|
||||
u8 *trace_bits; /* SHM with instrumentation bitmap */
|
||||
u8 use_stdin; /* use stdin for sending data */
|
||||
|
||||
s32 fsrv_pid, /* PID of the fork server */
|
||||
child_pid, /* PID of the fuzzed program */
|
||||
out_dir_fd; /* FD of the lock file */
|
||||
|
||||
s32 out_fd, /* Persistent fd for fsrv->out_file */
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
dev_urandom_fd, /* Persistent fd for /dev/urandom */
|
||||
#endif
|
||||
dev_null_fd, /* Persistent fd for /dev/null */
|
||||
fsrv_ctl_fd, /* Fork server control pipe (write) */
|
||||
fsrv_st_fd; /* Fork server status pipe (read) */
|
||||
|
||||
u32 exec_tmout; /* Configurable exec timeout (ms) */
|
||||
u64 mem_limit; /* Memory cap for child (MB) */
|
||||
|
||||
u8 *out_file, /* File to fuzz, if any */
|
||||
*target_path; /* Path of the target */
|
||||
|
||||
FILE *plot_file; /* Gnuplot output file */
|
||||
|
||||
u8 child_timed_out; /* Traced process timed out? */
|
||||
|
||||
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
|
||||
|
||||
u32 prev_timed_out; /* if prev forkserver run timed out */
|
||||
|
||||
} afl_forkserver_t;
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv);
|
||||
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_killall();
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define MSG_FORK_ON_APPLE \
|
||||
|
182
include/list.h
Normal file
182
include/list.h
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
american fuzzy lop++ - linked list code
|
||||
---------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 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
|
||||
|
||||
This allocator is not designed to resist malicious attackers (the canaries
|
||||
are small and predictable), but provides a robust and portable way to detect
|
||||
use-after-free, off-by-one writes, stale pointers, and so on.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef AFL_LIST
|
||||
#define AFL_LIST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "afl-prealloc.h"
|
||||
|
||||
/* How many elements to allocate before malloc is needed */
|
||||
#define LIST_PREALLOC_SIZE (64)
|
||||
|
||||
typedef struct list_element {
|
||||
|
||||
PREALLOCABLE;
|
||||
|
||||
struct list_element *prev;
|
||||
struct list_element *next;
|
||||
void * data;
|
||||
|
||||
} element_t;
|
||||
|
||||
typedef struct list {
|
||||
|
||||
element_t element_prealloc_buf[LIST_PREALLOC_SIZE];
|
||||
u32 element_prealloc_count;
|
||||
|
||||
} list_t;
|
||||
|
||||
static inline element_t *get_head(list_t *list) {
|
||||
|
||||
/* The first element is the head */
|
||||
return list->element_prealloc_buf;
|
||||
|
||||
}
|
||||
|
||||
static inline void list_free_el(list_t *list, element_t *el) {
|
||||
|
||||
PRE_FREE(el, list->element_prealloc_count);
|
||||
|
||||
}
|
||||
|
||||
static inline void list_append(list_t *list, void *el) {
|
||||
|
||||
element_t *head = get_head(list);
|
||||
if (!head->next) {
|
||||
|
||||
/* initialize */
|
||||
|
||||
memset(list, 0, sizeof(list_t));
|
||||
PRE_ALLOC_FORCE(head, list->element_prealloc_count);
|
||||
head->next = head->prev = head;
|
||||
|
||||
}
|
||||
|
||||
element_t *el_box = NULL;
|
||||
PRE_ALLOC(el_box, list->element_prealloc_buf, LIST_PREALLOC_SIZE,
|
||||
list->element_prealloc_count);
|
||||
if (!el_box) FATAL("failed to allocate list element");
|
||||
el_box->data = el;
|
||||
el_box->next = head;
|
||||
el_box->prev = head->prev;
|
||||
head->prev->next = el_box;
|
||||
head->prev = el_box;
|
||||
|
||||
}
|
||||
|
||||
/* Simple foreach.
|
||||
Pointer to the current element is in `el`,
|
||||
casted to (a pointer) of the given `type`.
|
||||
A return from this block will return from calling func.
|
||||
*/
|
||||
|
||||
#define LIST_FOREACH(list, type, block) \
|
||||
do { \
|
||||
\
|
||||
list_t * li = (list); \
|
||||
element_t *head = get_head((li)); \
|
||||
element_t *el_box = (head)->next; \
|
||||
if (!el_box) FATAL("foreach over uninitialized list"); \
|
||||
while (el_box != head) { \
|
||||
\
|
||||
__attribute__((unused)) type *el = (type *)((el_box)->data); \
|
||||
/* get next so el_box can be unlinked */ \
|
||||
element_t *next = el_box->next; \
|
||||
{block}; \
|
||||
el_box = next; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* In foreach: remove the current el from the list */
|
||||
|
||||
#define LIST_REMOVE_CURRENT_EL_IN_FOREACH() \
|
||||
do { \
|
||||
\
|
||||
el_box->prev->next = next; \
|
||||
el_box->next->prev = el_box->prev; \
|
||||
list_free_el(li, el_box); \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* Same as foreach, but will clear list in the process */
|
||||
|
||||
#define LIST_FOREACH_CLEAR(list, type, block) \
|
||||
do { \
|
||||
\
|
||||
LIST_FOREACH((list), type, { \
|
||||
\
|
||||
{block}; \
|
||||
LIST_REMOVE_CURRENT_EL_IN_FOREACH(); \
|
||||
\
|
||||
}); \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* remove an item from the list */
|
||||
|
||||
static inline void list_remove(list_t *list, void *remove_me) {
|
||||
|
||||
LIST_FOREACH(list, void, {
|
||||
|
||||
if (el == remove_me) {
|
||||
|
||||
el_box->prev->next = el_box->next;
|
||||
el_box->next->prev = el_box->prev;
|
||||
el_box->data = NULL;
|
||||
list_free_el(list, el_box);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
FATAL("List item to be removed not in list");
|
||||
|
||||
}
|
||||
|
||||
/* Returns true if el is in list */
|
||||
|
||||
static inline bool list_contains(list_t *list, void *contains_me) {
|
||||
|
||||
LIST_FOREACH(list, void, {
|
||||
|
||||
if (el == contains_me) return true;
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,8 +7,9 @@
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,11 +28,32 @@
|
||||
#ifndef __AFL_SHAREDMEM_H
|
||||
#define __AFL_SHAREDMEM_H
|
||||
|
||||
void setup_shm(unsigned char dumb_mode);
|
||||
void remove_shm(void);
|
||||
typedef struct sharedmem {
|
||||
|
||||
extern int cmplog_mode;
|
||||
extern struct cmp_map* cmp_map;
|
||||
// extern unsigned char *trace_bits;
|
||||
|
||||
#ifdef USEMMAP
|
||||
/* ================ Proteas ================ */
|
||||
int g_shm_fd;
|
||||
char g_shm_file_path[L_tmpnam];
|
||||
/* ========================================= */
|
||||
#else
|
||||
s32 shm_id; /* ID of the SHM region */
|
||||
s32 cmplog_shm_id;
|
||||
#endif
|
||||
|
||||
u8 *map; /* shared memory region */
|
||||
|
||||
size_t size_alloc; /* actual allocated size */
|
||||
size_t size_used; /* in use by shmem app */
|
||||
|
||||
int cmplog_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
} sharedmem_t;
|
||||
|
||||
u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char dumb_mode);
|
||||
void afl_shm_deinit(sharedmem_t *);
|
||||
|
||||
#endif
|
||||
|
||||
|
59
include/snapshot-inl.h
Normal file
59
include/snapshot-inl.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
american fuzzy lop++ - snapshot helpers routines
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 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
|
||||
|
||||
*/
|
||||
|
||||
// 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 <fcntl.h>
|
||||
|
||||
#define AFL_SNAPSHOT_FILE_NAME "/dev/afl_snapshot"
|
||||
|
||||
#define AFL_SNAPSHOT_IOCTL_MAGIC 44313
|
||||
|
||||
#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1)
|
||||
#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2)
|
||||
|
||||
static int afl_snapshot_dev_fd;
|
||||
|
||||
static int afl_snapshot_init(void) {
|
||||
|
||||
afl_snapshot_dev_fd = open(AFL_SNAPSHOT_FILE_NAME, 0);
|
||||
return afl_snapshot_dev_fd;
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_do() {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO);
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_clean(void) {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN);
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -57,8 +58,22 @@ typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a))
|
||||
#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
#define MAX(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
#endif /* !MIN */
|
||||
|
||||
#define SWAP16(_x) \
|
||||
@ -119,9 +134,13 @@ typedef int64_t s64;
|
||||
#define likely(_x) (_x)
|
||||
#define unlikely(_x) (_x)
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(_x) __builtin_expect(!!(_x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) __builtin_expect(!!(_x), 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ! _HAVE_TYPES_H */
|
||||
|
||||
|
@ -18,18 +18,17 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS += -I ../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
ifdef USEHUGEPAGE
|
||||
CFLAGS += -DUSEHUGEPAGE
|
||||
endif
|
||||
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
|
||||
all: libdislocator.so
|
||||
|
||||
VPATH = ..
|
||||
libdislocator.so: libdislocator.so.c ../config.h
|
||||
$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -shared -fPIC libdislocator.so.c -o ../$@ $(LDFLAGS)
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# libdislocator, an abusive allocator
|
||||
|
||||
(See ../docs/README for the general instruction manual.)
|
||||
(See ../docs/README.md for the general instruction manual.)
|
||||
|
||||
This is a companion library that can be used as a drop-in replacement for the
|
||||
libc allocator in the fuzzed binaries. It improves the odds of bumping into
|
||||
|
63
libtokencap/GNUmakefile
Normal file
63
libtokencap/GNUmakefile
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# american fuzzy lop++ - libtokencap
|
||||
# --------------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2016 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
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
override CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
|
||||
|
||||
ifeq "$(shell uname)" "Linux"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "FreeBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "NetBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "DragonFly"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
all: $(TARGETS)
|
||||
|
||||
VPATH = ..
|
||||
libtokencap.so: libtokencap.so.c ../config.h
|
||||
$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
|
||||
rm -f ../libtokencap.so
|
||||
|
||||
install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
|
||||
|
@ -15,33 +15,56 @@
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS += -I ../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
ifeq "$(shell uname)" "Linux"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "FreeBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "NetBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "DragonFly"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
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_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)$(UNAME_S)=)
|
||||
|
||||
TARGETS = $(____OS_TARGET:$(_UNIQ)=libtokencap.so)
|
||||
|
||||
LDFLAGS += $(______OS_DL)
|
||||
|
||||
#ifeq "$(shell uname)" "Linux"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "Darwin"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "FreeBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "OpenBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "NetBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "DragonFly"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
all: $(TARGETS)
|
||||
|
||||
VPATH = ..
|
||||
@ -50,6 +73,16 @@ libtokencap.so: libtokencap.so.c ../config.h
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
debug:
|
||||
@echo $(UNAME_S)$(_UNIQ) | hexdump -C
|
||||
@echo from $(____OS_DL) : $(_UNIQ)$(UNAME_S) = -\> $(_____OS_DL)
|
||||
@echo from $(_____OS_DL) : $(_UNIQ) = -ldl -\> $(______OS_DL)
|
||||
@echo from $(____OS_DL) : $(_UNIQ)FreeBSD = $(_UNIQ) -\> $(_OS_TARGET)
|
||||
@echo from $(_OS_TARGET) : $(_UNIQ)OpenBSD = $(_UNIQ) -\> $(__OS_TARGET)
|
||||
@echo from $(__OS_TARGET) : $(_UNIQ)NetBSD = $(_UNIQ) -\> $(___OS_TARGET)
|
||||
@echo from $(___OS_TARGET) : $(_UNIQ)$(_UNIQ) = -\> $(____OS_TARGET)
|
||||
@echo from $(____OS_TARGET) : $(_UNIQ) = libtokencap.so -\> $(TARGETS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
|
||||
rm -f ../libtokencap.so
|
||||
@ -57,5 +90,4 @@ clean:
|
||||
install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 README.tokencap.md $${DESTDIR}$(HELPER_PATH)
|
||||
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
|
||||
|
@ -1,6 +1,6 @@
|
||||
# strcmp() / memcmp() token capture library
|
||||
|
||||
(See ../docs/README for the general instruction manual.)
|
||||
(See ../docs/README.md for the general instruction manual.)
|
||||
|
||||
This companion library allows you to instrument `strcmp()`, `memcmp()`,
|
||||
and related functions to automatically extract syntax tokens passed to any of
|
||||
|
366
llvm_mode/GNUmakefile
Normal file
366
llvm_mode/GNUmakefile
Normal file
@ -0,0 +1,366 @@
|
||||
#
|
||||
# american fuzzy lop++ - LLVM instrumentation
|
||||
# -----------------------------------------
|
||||
#
|
||||
# Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# LLVM integration design comes from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015, 2016 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
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MISC_PATH ?= $(PREFIX)/share/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
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.8.0 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-7]|^1[2-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-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_STDCXX = gnu++11
|
||||
LLVM_APPLE = $(shell clang -v 2>&1 | grep -iq apple && echo 1 || echo 0)
|
||||
LLVM_LTO = 0
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning [!] llvm_mode needs llvm-config, which was not found)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.8.0 up to 11)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
$(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
$(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
|
||||
LLVM_STDCXX = c++14
|
||||
LLVM_LTO = 1
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "0"
|
||||
$(info [+] llvm_mode detected llvm < 9, afl-clang-lto LTO will not be build.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE)" "1"
|
||||
$(warning llvm_mode will not compile with Xcode clang...)
|
||||
endif
|
||||
|
||||
# We were using llvm-config --bindir to get the location of clang, but
|
||||
# this seems to be busted on some distros, so using the one in $PATH is
|
||||
# probably better.
|
||||
|
||||
CC = $(LLVM_BINDIR)/clang
|
||||
CXX = $(LLVM_BINDIR)/clang++
|
||||
|
||||
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
|
||||
# llvm-config --bindir may not providing a valid path, so ...
|
||||
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
|
||||
# we found one in the local install directory, lets use these
|
||||
CC = $(BIN_DIR)/clang
|
||||
CXX = $(BIN_DIR)/clang++
|
||||
else
|
||||
# hope for the best
|
||||
$(warning we have trouble finding clang/clang++ - llvm-config is not helping us)
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
endif
|
||||
endif
|
||||
|
||||
# sanity check.
|
||||
# Are versions of clang --version and llvm-config --version equal?
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
CC = $(shell $(LLVM_CONFIG) --bindir)/clang
|
||||
CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
|
||||
endif
|
||||
|
||||
# After we set CC/CXX we can start makefile magic tests
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_OPT = -march=native
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(AFL_REAL_LD)" ""
|
||||
AFL_REAL_LD = $(shell readlink /bin/ld 2>/dev/null)
|
||||
ifeq "$(AFL_REAL_LD)" ""
|
||||
AFL_REAL_LD = $(shell readlink /usr/bin/ld 2>/dev/null)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
AFL_CLANG_FUSELD=
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -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
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CFLAGS = -Wall \
|
||||
-g -Wno-pointer-sign -I ../include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_VERSION=\"$(LLVMVER)\" -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
|
||||
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" -Wno-unused-function
|
||||
ifdef AFL_TRACE_PC
|
||||
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CXXFLAGS += -Wall -g -I ../include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros
|
||||
|
||||
CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS)
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
PROGS = ../afl-clang-fast ../afl-ld ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE)" "00"
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = no_build
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done
|
||||
endif
|
||||
|
||||
LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE)" "1"
|
||||
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
|
||||
@echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang"
|
||||
else
|
||||
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
|
||||
endif
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
|
||||
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
|
||||
ln -sf afl-clang-fast ../afl-clang-fast++
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ln -sf afl-clang-fast ../afl-clang-lto
|
||||
ln -sf afl-clang-fast ../afl-clang-lto++
|
||||
endif
|
||||
endif
|
||||
|
||||
../afl-ld: afl-ld.c
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
ln -sf afl-ld ../ld
|
||||
@rm -f .test-instr
|
||||
@-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -Wl,--afl -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto and afl-ld seem to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto"
|
||||
@rm -f .test-instr
|
||||
endif
|
||||
endif
|
||||
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps
|
||||
-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps
|
||||
ifeq "$(LLVM_MIN_4_0_1)" "0"
|
||||
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
|
||||
endif
|
||||
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
|
||||
endif
|
||||
|
||||
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc MarkNodes.cc
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
|
||||
endif
|
||||
|
||||
# laf
|
||||
../split-switches-pass.so: split-switches-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../compare-transform-pass.so: compare-transform-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../split-compares-pass.so: split-compares-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
# /laf
|
||||
|
||||
../cmplog-routines-pass.so: cmplog-routines-pass.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CFLAGS) -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)... "
|
||||
@$(CC) $(CFLAGS) -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..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-clang-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
install: all
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-clang-lto -a -f ../afl-ld ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-ld $${DESTDIR}$(HELPER_PATH); ln -sf afl-ld $${DESTDIR}$(HELPER_PATH)/ld; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
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; 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
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-fast++.8
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-lto.8
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-lto++.8
|
||||
endif
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
|
||||
rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld
|
@ -54,6 +54,8 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
uint32_t function_minimum_size = 1;
|
||||
uint32_t debug = 0;
|
||||
|
||||
private:
|
||||
std::mt19937 generator;
|
||||
@ -131,7 +133,7 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
char be_quiet = 0;
|
||||
|
||||
if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");
|
||||
|
||||
@ -139,10 +141,12 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG") != NULL) debug = 1;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
char *neverZero_counters_str;
|
||||
if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
|
||||
OKF("LLVM neverZero activated (by hexcoder)\n");
|
||||
if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n");
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
|
||||
@ -152,6 +156,9 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL)
|
||||
function_minimum_size = 2;
|
||||
|
||||
// this is our default
|
||||
MarkSetOpt = true;
|
||||
|
||||
@ -176,8 +183,19 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
for (Function &F : M) {
|
||||
|
||||
// if it is external or only contains one basic block: skip it
|
||||
if (F.size() < 2) { continue; }
|
||||
if (debug) {
|
||||
|
||||
uint32_t bb_cnt = 0;
|
||||
|
||||
for (auto &BB : F)
|
||||
if (BB.size() > 0) ++bb_cnt;
|
||||
SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n",
|
||||
F.getName().str().c_str(), F.size(), bb_cnt);
|
||||
|
||||
}
|
||||
|
||||
// if the function below our minimum size skip it (1 or 2)
|
||||
if (F.size() < function_minimum_size) { continue; }
|
||||
|
||||
if (!myWhitelist.empty()) {
|
||||
|
||||
@ -383,62 +401,13 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
// Bugfix #1: remove single block function instrumentation
|
||||
if (function_minimum_size < 2) {
|
||||
|
||||
for (BasicBlock &BB : F) {
|
||||
|
||||
if (MarkSetOpt && MS.find(&BB) == MS.end()) {
|
||||
|
||||
// Bugfix #2: instrument blocks that should be but InsTrim
|
||||
// doesn't due to an algorithmic bug
|
||||
int more_than_one = -1;
|
||||
|
||||
for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); PI != E;
|
||||
++PI) {
|
||||
|
||||
BasicBlock *Pred = *PI;
|
||||
int count = 0;
|
||||
|
||||
if (more_than_one == -1) more_than_one = 0;
|
||||
for (succ_iterator SI = succ_begin(Pred), E = succ_end(Pred);
|
||||
SI != E; ++SI) {
|
||||
|
||||
BasicBlock *Succ = *SI;
|
||||
if (Succ != NULL) count++;
|
||||
|
||||
}
|
||||
|
||||
if (count > 1) more_than_one = 1;
|
||||
|
||||
}
|
||||
|
||||
if (more_than_one != 1) continue;
|
||||
for (succ_iterator SI = succ_begin(&BB), E = succ_end(&BB); SI != E;
|
||||
++SI) {
|
||||
|
||||
BasicBlock *Succ = *SI;
|
||||
if (Succ != NULL && MS.find(Succ) == MS.end()) {
|
||||
|
||||
int cnt = 0;
|
||||
for (succ_iterator SI2 = succ_begin(Succ), E2 = succ_end(Succ);
|
||||
SI2 != E2; ++SI2) {
|
||||
|
||||
BasicBlock *Succ2 = *SI2;
|
||||
if (Succ2 != NULL) cnt++;
|
||||
|
||||
}
|
||||
|
||||
if (cnt == 0) {
|
||||
|
||||
// fprintf(stderr, "INSERT!\n");
|
||||
MS.insert(Succ);
|
||||
total_rs += 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (MS.find(&BB) == MS.end()) { continue; }
|
||||
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
|
||||
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev);
|
||||
|
||||
}
|
||||
|
||||
@ -450,9 +419,17 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
|
||||
|
||||
auto PI = pred_begin(&BB);
|
||||
auto PE = pred_end(&BB);
|
||||
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
|
||||
Value * L = NULL;
|
||||
|
||||
if (function_minimum_size < 2 && PI == PE) {
|
||||
|
||||
L = ConstantInt::get(Int32Ty, genLabel());
|
||||
|
||||
} else {
|
||||
|
||||
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
|
||||
DenseMap<BasicBlock *, unsigned> PredMap;
|
||||
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
|
||||
@ -466,6 +443,8 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
L = PN;
|
||||
|
||||
}
|
||||
|
||||
/* Load prev_loc */
|
||||
LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
|
||||
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
@ -512,27 +491,36 @@ struct InsTrim : public ModulePass {
|
||||
IRB.CreateStore(Incr, MapPtrIdx)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
// Bugfix #3: save the actually location ID to OldPrev
|
||||
// save the actually location ID to OldPrev if function_minimum_size > 1
|
||||
if (function_minimum_size > 1) {
|
||||
|
||||
Value *Shr = IRB.CreateLShr(L, One32);
|
||||
IRB.CreateStore(Shr, OldPrev)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
}
|
||||
|
||||
total_instr++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
char modeline[100];
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
|
||||
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
|
||||
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
|
||||
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
|
||||
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr,
|
||||
total_rs, total_hs, modeline);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -1,273 +1,2 @@
|
||||
#
|
||||
# american fuzzy lop++ - LLVM instrumentation
|
||||
# -----------------------------------------
|
||||
#
|
||||
# Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# LLVM integration design comes from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015, 2016 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
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
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.8.0 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-7]|^1[2-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-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_STDCXX = gnu++11
|
||||
LLVM_APPLE = $(shell clang -v 2>&1 | grep -iq apple && echo 1 || echo 0)
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning llvm_mode needs llvm-config, which was not found)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.8.0 up to 11)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
LLVM_STDCXX = c++14
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE)" "1"
|
||||
$(warning llvm_mode will not compile with Xcode clang...)
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I ../include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_VERSION=\"$(LLVMVER)\"
|
||||
ifdef AFL_TRACE_PC
|
||||
CFLAGS += -DUSE_TRACE_PC=1
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops
|
||||
CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -I ../include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros
|
||||
|
||||
CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS)
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
endif
|
||||
|
||||
# We were using llvm-config --bindir to get the location of clang, but
|
||||
# this seems to be busted on some distros, so using the one in $PATH is
|
||||
# probably better.
|
||||
|
||||
CC = $(LLVM_BINDIR)/clang
|
||||
CXX = $(LLVM_BINDIR)/clang++
|
||||
|
||||
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
|
||||
# llvm-config --bindir is not providing a valid path, so ...
|
||||
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
|
||||
# we found one in the local install directory, lets use these
|
||||
CC = $(BIN_DIR)/clang
|
||||
CXX = $(BIN_DIR)/clang++
|
||||
else
|
||||
# hope for the best
|
||||
$(warning we have trouble finding clang/clang++ - llvm-config is not helping us)
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
endif
|
||||
endif
|
||||
|
||||
# sanity check.
|
||||
# Are versions of clang --version and llvm-config --version equal?
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifndef AFL_TRACE_PC
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so
|
||||
else
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so
|
||||
endif
|
||||
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
CC = $(shell $(LLVM_CONFIG) --bindir)/clang
|
||||
CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
|
||||
endif
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE)" "00"
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = no_build
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done
|
||||
endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
test_deps:
|
||||
ifndef AFL_TRACE_PC
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE)" "1"
|
||||
@which $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
|
||||
endif
|
||||
else
|
||||
@echo "[!] Note: using -fsanitize=trace-pc mode (this will fail with older LLVM)."
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
|
||||
@echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang"
|
||||
else
|
||||
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
|
||||
endif
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
|
||||
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-clang-fast ../afl-clang-fast++
|
||||
|
||||
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps
|
||||
-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
# laf
|
||||
../split-switches-pass.so: split-switches-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../compare-transform-pass.so: compare-transform-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../split-compares-pass.so: split-compares-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
# /laf
|
||||
|
||||
../cmplog-routines-pass.so: cmplog-routines-pass.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CFLAGS) -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)... "
|
||||
@$(CC) $(CFLAGS) -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..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-clang-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-fast++.8
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 afl-llvm-pass.dwo
|
||||
rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-fast*.8
|
||||
all:
|
||||
@echo please use GNU make, thanks!
|
||||
|
@ -376,10 +376,10 @@ void MakeUniq(uint32_t now) {
|
||||
|
||||
}
|
||||
|
||||
void MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
bool MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
|
||||
TopologicalSort(ss, tt);
|
||||
if (TopoOrder.empty()) return;
|
||||
if (TopoOrder.empty()) return false;
|
||||
|
||||
for (uint32_t i : TopoOrder) {
|
||||
|
||||
@ -394,6 +394,10 @@ void MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
|
||||
}
|
||||
|
||||
// Check if there is an empty path.
|
||||
if (NextMarked[tt].count(TopoOrder[0]) > 0) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void MarkVertice() {
|
||||
@ -417,14 +421,22 @@ void MarkVertice() {
|
||||
|
||||
timeStamp = 0;
|
||||
uint32_t t = 0;
|
||||
bool emptyPathExists = true;
|
||||
|
||||
while (s != t) {
|
||||
|
||||
MarkSubGraph(DominatorTree::idom[t], t);
|
||||
emptyPathExists &= MarkSubGraph(DominatorTree::idom[t], t);
|
||||
t = DominatorTree::idom[t];
|
||||
|
||||
}
|
||||
|
||||
if (emptyPathExists) {
|
||||
|
||||
// Mark all exit blocks to catch the empty path.
|
||||
Marked.insert(t_Pred[0].begin(), t_Pred[0].end());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return {marked nodes}
|
||||
|
88
llvm_mode/NOTES
Normal file
88
llvm_mode/NOTES
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
markNodes
|
||||
->
|
||||
|
||||
whitelist:
|
||||
set meta information/context to functions? ask llvm-dev
|
||||
setAttribute/hasAttribute?
|
||||
|
||||
afl-ld:
|
||||
handle(=instrument) .a archives on the cmdline
|
||||
|
||||
afl-pass-lto-instrument.so:
|
||||
either a or b:
|
||||
a) use instrim
|
||||
b) start in main() or _init() and first otherwise (warn!)
|
||||
keep list of done functions
|
||||
final: go through function list and instrument those missing
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
|
||||
|
||||
|
||||
for (auto &module : Ctx.getModules()) {
|
||||
auto &functionList = module->getModule()->getFunctionList();
|
||||
for (auto &function : functionList) {
|
||||
for (auto &bb : function) {
|
||||
for (auto &instruction : bb) {
|
||||
if (CallInst *callInst = dyn_cast<CallInst>(&instruction)) {
|
||||
if (Function *calledFunction = callInst->getCalledFunction()) {
|
||||
if (calledFunction->getName().startswith("llvm.dbg.declare")) {
|
||||
|
||||
|
||||
for (auto &U : F.getUsers()) { <- unbekannt
|
||||
if (auto CS = CallSite(U)) {
|
||||
if (CS->getCalledFunction() == F)
|
||||
|
||||
getCalledValue()->stripPointerCasts()
|
||||
-> for indirect calls
|
||||
|
||||
|
||||
CallGraph(M)
|
||||
|
||||
|
||||
|
||||
#include "llvm/IR/CallSite.h"
|
||||
|
||||
unsigned int indirect_call_cnt = 0;
|
||||
|
||||
printf("Function: %s\n", F.getName().str().c_str());
|
||||
int cnt=0;
|
||||
for (auto *U : F.users()) {
|
||||
// auto *I = dyn_cast<Instruction>(U);
|
||||
// if (I) {
|
||||
// if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) {
|
||||
// printf("DIRECT CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str());
|
||||
// }
|
||||
printf("Callsite #%d\n", ++cnt);
|
||||
CallSite CS(U);
|
||||
auto *I = CS.getInstruction();
|
||||
if (I) {
|
||||
Value *called = CS.getCalledValue()->stripPointerCasts();
|
||||
Function* f = dyn_cast<Function>(called);
|
||||
if (f->getName().size() > 0) {
|
||||
printf("test %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str());
|
||||
if (f->getName() == F.getName()) {
|
||||
printf("CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str());
|
||||
}
|
||||
} else
|
||||
printf("FOO %s->...->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), F.getName().str().c_str());
|
||||
if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) {
|
||||
printf("DIRECT %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str());
|
||||
}
|
||||
} else {
|
||||
printf("WE MISSED SOMETHING HERE!!\n");
|
||||
indirect_call_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
oder:
|
||||
for (auto *U : F.users()) {
|
||||
if (auto CS = CallSite(U->getUser())) {
|
||||
if (CS->isCallee(&U)) {
|
||||
// foo
|
||||
}
|
||||
}
|
||||
}
|
22
llvm_mode/README.ctx.md
Normal file
22
llvm_mode/README.ctx.md
Normal file
@ -0,0 +1,22 @@
|
||||
# AFL Context Sensitive Branch Coverage
|
||||
|
||||
## What is this?
|
||||
|
||||
This is an LLVM-based implementation of the context sensitive branch coverage.
|
||||
|
||||
Basically every function gets it's own ID and that ID is combined with the
|
||||
edges of the called functions.
|
||||
|
||||
So if both function A and function B call a function C, the coverage
|
||||
collected in C will be different.
|
||||
|
||||
In math the coverage is collected as follows:
|
||||
`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1`
|
||||
|
||||
## Usage
|
||||
|
||||
Set the `AFL_LLVM_INSTRUMENT=CTX` or `AFL_LLVM_CTX=1` environment variable.
|
||||
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
@ -5,13 +5,12 @@ InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing
|
||||
## Introduction
|
||||
|
||||
InsTrim uses CFG and markers to instrument just what is necessary in the
|
||||
binary in llvm_mode. It is about 20-25% faster but as a cost has a lower
|
||||
path discovery.
|
||||
binary in llvm_mode. It is about 10-15% faster without disadvantages.
|
||||
|
||||
## Usage
|
||||
|
||||
Set the environment variable `AFL_LLVM_INSTRIM=1` during compilation of
|
||||
the target.
|
||||
Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1`
|
||||
during compilation of the target.
|
||||
|
||||
There is also an advanced mode which instruments loops in a way so that
|
||||
afl-fuzz can see which loop path has been selected but not being able to
|
||||
@ -19,6 +18,15 @@ see how often the loop has been rerun.
|
||||
This again is a tradeoff for speed for less path information.
|
||||
To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
|
||||
|
||||
There is an additional optimization option that skips single block
|
||||
functions. In 95% of the C targets and (guess) 50% of the C++ targets
|
||||
it is good to enable this, as otherwise pointless instrumentation occurs.
|
||||
The corner case where we want this instrumentation is when vtable/call table
|
||||
is used and the index to that vtable/call table is not set in specific
|
||||
basic blocks.
|
||||
To enable skipping these (most of the time) unnecessary instrumentations set
|
||||
`AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1`
|
||||
|
||||
## Background
|
||||
|
||||
The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]
|
||||
|
262
llvm_mode/README.lto.md
Normal file
262
llvm_mode/README.lto.md
Normal file
@ -0,0 +1,262 @@
|
||||
# afl-clang-lto - collision free instrumentation at link time
|
||||
|
||||
## TLDR;
|
||||
|
||||
1. This compile mode is very frickle if it works it is amazing, if it fails
|
||||
- well use afl-clang-fast
|
||||
|
||||
2. 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
|
||||
|
||||
3. You can use it together with llvm_mode: laf-intel and whitelisting
|
||||
features and can be combined with cmplog/Redqueen
|
||||
|
||||
4. It only works with llvm 9 (and likely 10+ but is not tested there yet)
|
||||
|
||||
## Introduction and problem description
|
||||
|
||||
A big issue with how afl/afl++ works is that the basic block IDs that are
|
||||
set during compilation are random - and hence natually the larger the number
|
||||
of instrumented locations, the higher the number of edge collisions in the
|
||||
map. This can result in not discovering new paths and therefore degrade the
|
||||
efficiency of the fuzzing.
|
||||
|
||||
*This issue is understimated in the fuzzing community!*
|
||||
With a 2^16 = 64kb standard map at already 256 instrumented blocks there is
|
||||
on average one collision. On average a target has 10.000 to 50.000
|
||||
instrumented blocks hence the real collisions are between 750-18.000!
|
||||
|
||||
To get to a solution that prevents any collision took several approaches
|
||||
and many dead ends until we got to this:
|
||||
|
||||
* We instrument at link time when we have all files pre-compiled
|
||||
* To instrument at link time we compile in LTO (link time optimization) mode
|
||||
* Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the
|
||||
correct LTO options and runs our own afl-ld linker instead of the system
|
||||
linker
|
||||
* Our linker collects all LTO files to link and instruments them so that
|
||||
we have non-colliding edge overage
|
||||
* We use a new (for afl) edge coverage - which is the same as in llvm
|
||||
-fsanitize=coverage edge coverage mode :)
|
||||
* after inserting our instrumentation in all interesting edges we link
|
||||
all parts of the program together to our executable
|
||||
|
||||
The result:
|
||||
* 10-15% speed gain compared to llvm_mode
|
||||
* guaranteed non-colliding edge coverage :-)
|
||||
* The compile time especially for libraries can be longer
|
||||
|
||||
Example build output from a libtiff build:
|
||||
```
|
||||
/bin/bash ../libtool --tag=CC --mode=link afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm
|
||||
libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm
|
||||
afl-clang-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
|
||||
afl-ld++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de> (level 0)
|
||||
[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir
|
||||
[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir
|
||||
[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll
|
||||
[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc
|
||||
[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc
|
||||
afl-llvm-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
|
||||
[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
|
||||
[+] Running real linker /bin/x86_64-linux-gnu-ld
|
||||
[+] Linker was successful
|
||||
```
|
||||
|
||||
## How to use afl-clang-lto
|
||||
|
||||
Just use afl-clang-lto like you did afl-clang-fast or afl-gcc.
|
||||
|
||||
Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and
|
||||
laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
|
||||
Instrim does not - but we can not really use it anyway for our approach.
|
||||
|
||||
Example:
|
||||
```
|
||||
CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
|
||||
make
|
||||
```
|
||||
|
||||
## Potential issues
|
||||
|
||||
### compiling libraries fails
|
||||
|
||||
If you see this message:
|
||||
```
|
||||
/bin/ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one
|
||||
```
|
||||
This is because usually gnu gcc ranlib is being called which cannot deal with clang LTO files.
|
||||
The solution is simple: when you ./configure you have also have to set RANLIB=llvm-ranlib and AR=llvm-ar
|
||||
|
||||
Solution:
|
||||
```
|
||||
AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared
|
||||
```
|
||||
and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ...
|
||||
|
||||
### "linking globals named '...': symbol multiply defined" error
|
||||
|
||||
The target program is using multiple global variables or functions with the
|
||||
same name. This is a common error when compiling a project with LTO, and
|
||||
the fix is `-Wl,--allow-multiple-definition` - however llvm-link which we
|
||||
need to link all llvm IR LTO files does not support this - yet (hopefully).
|
||||
Hence if you see this error either you have to remove the duplicate global
|
||||
variable (think `#ifdef` ...) or you are out of luck. :-(
|
||||
|
||||
### "expected top-level entity" + binary ouput error
|
||||
|
||||
This happens if multiple .a archives are to be linked and they contain the
|
||||
same object filenames, the first in LTO form, the other in ELF form.
|
||||
This can not be fixed programmatically, but can be fixed by hand.
|
||||
You can try to delete the file from either archive
|
||||
(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
|
||||
and instrumentation by hand (see below).
|
||||
|
||||
### "undefined reference to ..."
|
||||
|
||||
This *can* be the opposite situation of the "expected top-level entity" error -
|
||||
the library with the ELF file is before the LTO library.
|
||||
However it can also be a bug in the program - try to compile it normally. If
|
||||
fails then it is a bug in the program.
|
||||
Solutions: You can try to delete the file from either archive, e.g.
|
||||
(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
|
||||
and instrumentation by hand (see below).
|
||||
|
||||
### "File format not recognized"
|
||||
|
||||
This happens if the build system has fixed LDFLAGS, CPPFLAGS, CXXFLAGS and/or
|
||||
CFLAGS. Ensure that they all contain the `-flto` flag that afl-clang-lto was
|
||||
compiled with (you can see that by typing `afl-clang-lto -h` and inspecting
|
||||
the last line of the help output) and add them otherwise
|
||||
|
||||
### clang is hardcoded to /bin/ld
|
||||
|
||||
Some clang packages have 'ld' hardcoded to /bin/ld. This is an issue as this
|
||||
prevents "our" afl-ld being called.
|
||||
|
||||
-fuse-ld=/path/to/afl-ld should be set through makefile magic in llvm_mode -
|
||||
if it is supported - however if this fails you can try:
|
||||
```
|
||||
LDFLAGS=-fuse-ld=</path/to/afl-ld
|
||||
```
|
||||
|
||||
As workaround attempt #2 you will have to switch /bin/ld:
|
||||
```
|
||||
mv /bin/ld /bin/ld.orig
|
||||
cp afl-ld /bin/ld
|
||||
```
|
||||
This can result in two problems though:
|
||||
|
||||
!1!
|
||||
When compiling afl-ld, the build process looks at where the /bin/ld link
|
||||
is going to. So when the workaround was applied and a recompiling afl-ld
|
||||
is performed then the link is gone and the new afl-ld clueless where
|
||||
the real ld is.
|
||||
In this case set AFL_REAL_LD=/bin/ld.orig
|
||||
|
||||
!2!
|
||||
When you install an updated gcc/clang/... package, your OS might restore
|
||||
the ld link.
|
||||
|
||||
### Performing the steps by hand
|
||||
|
||||
It is possible to perform all the steps afl-ld by hand to workaround issues
|
||||
in the target.
|
||||
|
||||
1. Recompile with AFL_DEBUG=1 and collect the afl-clang-lto command that fails
|
||||
e.g.: `AFL_DEBUG=1 make 2>&1 | grep afl-clang-lto | tail -n 1`
|
||||
|
||||
2. run this command prepended with AFL_DEBUG=1 and collect the afl-ld command
|
||||
parameters, e.g. `AFL_DEBUG=1 afl-clang-lto[++] .... | grep /afl/ld`
|
||||
|
||||
3. for every .a archive you want to instrument unpack it into a seperate
|
||||
directory, e.g.
|
||||
`mkdir archive1.dir ; cd archive1.dir ; llvm-link x ../<archive>.a`
|
||||
|
||||
4. run `file archive*.dir/*.o` and make two lists, one containing all ELF files
|
||||
and one containing all LLVM IR bitcode files.
|
||||
You do the same for all .o files of the ../afl/ld command options
|
||||
|
||||
5. Create a single bitcode file by using llvm-link, e.g.
|
||||
`llvm-link -o all-bitcode.bc <list of all LLVM IR .o files>`
|
||||
If this fails it is game over - or you modify the source code
|
||||
|
||||
6. Run the optimizer on the new bitcode file:
|
||||
`opt -O3 --polly -o all-optimized.bc all-bitcode.bc`
|
||||
|
||||
7. Instrument the optimized bitcode file:
|
||||
`opt --load=$AFL_PATH/afl-llvm-lto-instrumentation.so --disable-opt --afl-lto all-optimized.bc -o all-instrumented.bc
|
||||
|
||||
8. If the parameter `--allow-multiple-definition` is not in the list, add it
|
||||
as first command line option.
|
||||
|
||||
9. Link everything together.
|
||||
a) You use the afl-ld command and instead of e.g. `/usr/local/lib/afl/ld`
|
||||
you replace that with `ld`, the real linker.
|
||||
b) Every .a archive you instrumented files from you remove the <archive>.a
|
||||
or -l<archive> from the command
|
||||
c) If you have entries in your ELF files list (see step 4), you put them to
|
||||
the command line - but them in the same order!
|
||||
d) put the all-instrumented.bc before the first library or .o file
|
||||
e) run the command and hope it compiles, if it doesn't you have to analyze
|
||||
what the issue is and fix that in the approriate step above.
|
||||
|
||||
Yes this is long and complicated. That is why there is afl-ld doing this and
|
||||
that why this can easily fail and not all different ways how it *can* fail can
|
||||
be implemented ...
|
||||
|
||||
### compiling programs still fail
|
||||
|
||||
afl-clang-lto is still work in progress.
|
||||
Complex targets are still likely not to compile and this needs to be fixed.
|
||||
Please report issues at:
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
|
||||
|
||||
Known issues:
|
||||
* ffmpeg
|
||||
* bogofilter
|
||||
* libjpeg-turbo-1.3.1
|
||||
|
||||
## Upcoming Work
|
||||
|
||||
1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions
|
||||
2. Modify the forkserver + afl-fuzz so that only the necessary map size is
|
||||
loaded and used - and communicated to afl-fuzz too.
|
||||
Result: faster fork in the target and faster map analysis in afl-fuzz
|
||||
=> more speed :-)
|
||||
|
||||
## Tested and working targets
|
||||
|
||||
* libpng-1.2.53
|
||||
* libxml2-2.9.2
|
||||
* tiff-4.0.4
|
||||
* unrar-nonfree-5.6.6
|
||||
* exiv 0.27
|
||||
* jpeg-6b
|
||||
|
||||
## History
|
||||
|
||||
This was originally envisioned by hexcoder- in Summer 2019, however we saw no
|
||||
way to create a pass that is run at link time - although there is a option
|
||||
for this in the PassManager: EP_FullLinkTimeOptimizationLast
|
||||
("Fun" info - nobody knows what this is doing. And the developer who
|
||||
implemented this didn't respond to emails.)
|
||||
|
||||
In December came then the idea to implement this as a pass that is run via
|
||||
the llvm "opt" program, which is performed via an own linker that afterwards
|
||||
calls the real linker.
|
||||
This was first implemented in January and work ... kinda.
|
||||
The LTO time instrumentation worked, however the "how" the basic blocks were
|
||||
instrumented was a problem, as reducing duplicates turned out to be very,
|
||||
very difficult with a program that has so many paths and therefore so many
|
||||
dependencies. At lot of stratgies were implemented - and failed.
|
||||
And then sat solvers were tried, but with over 10.000 variables that turned
|
||||
out to be a dead-end too.
|
||||
The final idea to solve this came from domenukk who proposed to insert a block
|
||||
into an edge and then just use incremental counters ... and this worked!
|
||||
After some trials and errors to implement this vanhauser-thc found out that
|
||||
there is actually an llvm function for this: SplitEdge() :-)
|
||||
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.
|
||||
As long as there are no larger changes in llvm this all should work well now ...
|
@ -2,7 +2,7 @@
|
||||
|
||||
(See [../README](../README.md) for the general instruction manual.)
|
||||
|
||||
(See [../gcc_plugin/README.gcc](../gcc_plugin/README.gcc.md) for the GCC-based instrumentation.)
|
||||
(See [../gcc_plugin/README](../gcc_plugin/README.md) for the GCC-based instrumentation.)
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
@ -92,13 +92,33 @@ which C/C++ files to actually instrument. See [README.whitelist](README.whitelis
|
||||
|
||||
For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md)
|
||||
|
||||
Then there is an optimized instrumentation strategy that uses CFGs and
|
||||
markers to just instrument what is needed. This increases speed by 20-25%
|
||||
however has a lower path discovery.
|
||||
If you want to use this, set AFL_LLVM_INSTRIM=1
|
||||
Then there are different ways of instrumenting the target:
|
||||
|
||||
1. There is an optimized instrumentation strategy that uses CFGs and
|
||||
markers to just instrument what is needed. This increases speed by 10-15%
|
||||
without any disadvantages
|
||||
If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1
|
||||
See [README.instrim](README.instrim.md)
|
||||
|
||||
A new instrumentation called CmpLog is also available as an alternative to
|
||||
2. An even better instrumentation strategy uses LTO and link time
|
||||
instrumentation. Note that not all targets can compile in this mode, however
|
||||
if it works it is the best option you can use.
|
||||
Simply use afl-clang-lto/afl-clang-lto++ to use this option.
|
||||
See [README.lto](README.lto.md)
|
||||
|
||||
3. Alternativly you can choose a completely different coverage method:
|
||||
|
||||
3a. N-GRAM coverage - which combines the previous visited edges with the
|
||||
current one. This explodes the map but on the other hand has proven to be
|
||||
effective for fuzzing.
|
||||
See [README.ngram](README.ngram.md)
|
||||
|
||||
3b. Context sensitive coverage - which combines the visited edges with an
|
||||
individual caller ID (the function that called the current one)
|
||||
[README.ctx](README.ctx.md)
|
||||
|
||||
Then - additionally to one of the instrumentation options above - there is
|
||||
a very effective new instrumentation option called CmpLog as an alternative to
|
||||
laf-intel that allow AFL++ to apply mutations similar to Redqueen.
|
||||
See [README.cmplog](README.cmplog.md)
|
||||
|
||||
@ -109,12 +129,18 @@ is not optimal and was only fixed in llvm 9.
|
||||
You can set this with AFL_LLVM_NOT_ZERO=1
|
||||
See [README.neverzero](README.neverzero.md)
|
||||
|
||||
## 4) Gotchas, feedback, bugs
|
||||
## 4) Snapshot feature
|
||||
|
||||
To speed up fuzzing you can use a linux loadable kernel module which enables
|
||||
a snapshot feature.
|
||||
See [README.snapshot](README.snapshot.md)
|
||||
|
||||
## 5) Gotchas, feedback, bugs
|
||||
|
||||
This is an early-stage mechanism, so field reports are welcome. You can send bug
|
||||
reports to <afl-users@googlegroups.com>.
|
||||
|
||||
## 5) Bonus feature #1: deferred initialization
|
||||
## 6) Bonus feature #1: deferred initialization
|
||||
|
||||
AFL tries to optimize performance by executing the targeted binary just once,
|
||||
stopping it just before main(), and then cloning this "master" process to get
|
||||
@ -162,7 +188,7 @@ 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!
|
||||
|
||||
## 6) Bonus feature #2: persistent mode
|
||||
## 7) Bonus feature #2: persistent mode
|
||||
|
||||
Some libraries provide APIs that are stateless, or whose state can be reset in
|
||||
between processing different input files. When such a reset is performed, a
|
||||
|
28
llvm_mode/README.ngram.md
Normal file
28
llvm_mode/README.ngram.md
Normal file
@ -0,0 +1,28 @@
|
||||
# AFL N-Gram Branch Coverage
|
||||
|
||||
## Source
|
||||
|
||||
This is an LLVM-based implementation of the n-gram branch coverage proposed in
|
||||
the paper ["Be Sensitive and Collaborative: Analzying Impact of Coverage Metrics
|
||||
in Greybox Fuzzing"](https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf),
|
||||
by Jinghan Wang, et. al.
|
||||
|
||||
Note that the original implementation (available
|
||||
[here](https://github.com/bitsecurerlab/afl-sensitive))
|
||||
is built on top of AFL's QEMU mode.
|
||||
This is essentially a port that uses LLVM vectorized instructions to achieve
|
||||
the same results when compiling source code.
|
||||
|
||||
In math the branch coverage is performed as follows:
|
||||
`map[current_location ^ prev_location[0] >> 1 ^ prev_location[1] >> 1 ^ ... up to n-1`] += 1`
|
||||
|
||||
## Usage
|
||||
|
||||
The size of `n` (i.e., the number of branches to remember) is an option
|
||||
that is specified either in the `AFL_LLVM_INSTRUMENT=NGRAM-{value}` or the
|
||||
`AFL_LLVM_NGRAM_SIZE` environment variable.
|
||||
Good values are 2, 4 or 8, valid are 2-16.
|
||||
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
16
llvm_mode/README.snapshot.md
Normal file
16
llvm_mode/README.snapshot.md
Normal file
@ -0,0 +1,16 @@
|
||||
# AFL++ snapshot feature
|
||||
|
||||
Snapshotting is a feature that makes a snapshot from a process and then
|
||||
restores it's state, which is faster then forking it again.
|
||||
|
||||
All targets compiled with llvm_mode are automatically enabled for the
|
||||
snapshot feature.
|
||||
|
||||
To use the snapshot feature for fuzzing compile and load this kernel
|
||||
module: [https://github.com/AFLplusplus/AFL-Snapshot-LKM](https://github.com/AFLplusplus/AFL-Snapshot-LKM)
|
||||
|
||||
Note that is has little value for persistent (__AFL_LOOP) fuzzing.
|
||||
|
||||
## Notes
|
||||
|
||||
Snapshot does not work with multithreaded targets yet. Still in WIP, it is now usable only for single threaded applications.
|
10
llvm_mode/TODO
Normal file
10
llvm_mode/TODO
Normal file
@ -0,0 +1,10 @@
|
||||
TODO for afl-ld:
|
||||
* handle libfoo.a object archives
|
||||
|
||||
TODO for afl-llvm-lto-instrumentation:
|
||||
* better algo for putting stuff in the map?
|
||||
* try to predict how long the instrumentation process will take
|
||||
|
||||
TODO for afl-llvm-lto-whitelist
|
||||
* different solution then renaming?
|
||||
|
@ -29,11 +29,13 @@
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
#include "llvm-ngram-coverage.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
@ -41,9 +43,42 @@ static u8* obj_path; /* Path to runtime libraries */
|
||||
static u8 **cc_params; /* Parameters passed to the real CC */
|
||||
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
|
||||
static u8 llvm_fullpath[PATH_MAX];
|
||||
static u8 instrument_mode;
|
||||
static u8 * lto_flag = AFL_CLANG_FLTO;
|
||||
static u8 * march_opt = CFLAGS_OPT;
|
||||
static u8 debug;
|
||||
static u8 cwd[4096];
|
||||
static u8 cmplog_mode;
|
||||
u8 use_stdin = 0; /* dummy */
|
||||
|
||||
enum {
|
||||
|
||||
INSTRUMENT_CLASSIC = 0,
|
||||
INSTRUMENT_AFL = 0,
|
||||
INSTRUMENT_DEFAULT = 0,
|
||||
INSTRUMENT_PCGUARD = 1,
|
||||
INSTRUMENT_INSTRIM = 2,
|
||||
INSTRUMENT_CFG = 2,
|
||||
INSTRUMENT_LTO = 3,
|
||||
INSTRUMENT_CTX = 4,
|
||||
INSTRUMENT_NGRAM = 5 // + ngram value of 2-16 = 7 - 21
|
||||
|
||||
};
|
||||
|
||||
char instrument_mode_string[6][16] = {
|
||||
|
||||
"DEFAULT", "PCGUARD", "CFG", "LTO", "CTX",
|
||||
|
||||
};
|
||||
|
||||
u8 *getthecwd() {
|
||||
|
||||
static u8 fail[] = "";
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) return fail;
|
||||
return cwd;
|
||||
|
||||
}
|
||||
|
||||
/* Try to find the runtime libraries. If that fails, abort. */
|
||||
|
||||
static void find_obj(u8 *argv0) {
|
||||
@ -82,7 +117,7 @@ static void find_obj(u8* argv0) {
|
||||
*slash = '/';
|
||||
|
||||
#ifdef __ANDROID__
|
||||
tmp = alloc_printf("%s/afl-llvm-rt.so", afl_path);
|
||||
tmp = alloc_printf("%s/afl-llvm-rt.so", dir);
|
||||
#else
|
||||
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
|
||||
#endif
|
||||
@ -114,16 +149,16 @@ static void find_obj(u8* argv0) {
|
||||
}
|
||||
|
||||
FATAL(
|
||||
"Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so.cc'. Please set "
|
||||
"Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set "
|
||||
"AFL_PATH");
|
||||
|
||||
}
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char** argv) {
|
||||
static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0;
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
|
||||
u8 has_llvm_config = 0;
|
||||
u8 *name;
|
||||
|
||||
@ -137,7 +172,13 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
has_llvm_config = (strlen(LLVM_BINDIR) > 0);
|
||||
|
||||
if (!strcmp(name, "afl-clang-fast++")) {
|
||||
if (instrument_mode == INSTRUMENT_LTO)
|
||||
if (lto_flag[0] != '-')
|
||||
FATAL(
|
||||
"Using afl-clang-lto is not possible because Makefile magic did not "
|
||||
"identify the correct -flto flag");
|
||||
|
||||
if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) {
|
||||
|
||||
u8 *alt_cxx = getenv("AFL_CXX");
|
||||
if (has_llvm_config)
|
||||
@ -199,31 +240,63 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
// /laf
|
||||
|
||||
unsetenv("AFL_LD");
|
||||
unsetenv("AFL_LD_CALLER");
|
||||
if (cmplog_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard,trace-cmp";
|
||||
|
||||
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";
|
||||
|
||||
}
|
||||
|
||||
if (instrument_mode == INSTRUMENT_LTO) {
|
||||
|
||||
char *old_path = getenv("PATH");
|
||||
char *new_path = alloc_printf("%s:%s", AFL_PATH, old_path);
|
||||
|
||||
setenv("PATH", new_path, 1);
|
||||
setenv("AFL_LD", "1", 1);
|
||||
|
||||
if (getenv("AFL_LLVM_WHITELIST") != NULL) {
|
||||
|
||||
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/afl-llvm-lto-whitelist.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
#ifdef AFL_CLANG_FUSELD
|
||||
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s/afl-ld", AFL_PATH);
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt++] = "-B";
|
||||
cc_params[cc_par_cnt++] = AFL_PATH;
|
||||
|
||||
cc_params[cc_par_cnt++] = lto_flag;
|
||||
|
||||
} else {
|
||||
|
||||
#ifdef USE_TRACE_PC
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
|
||||
// cc_params[cc_par_cnt++] = "-mllvm";
|
||||
// cc_params[cc_par_cnt++] =
|
||||
// "-fsanitize-coverage=trace-cmp,trace-div,trace-gep";
|
||||
// cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
|
||||
#else
|
||||
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
|
||||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
|
||||
if (instrument_mode == INSTRUMENT_PCGUARD) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
|
||||
@ -233,7 +306,7 @@ static void edit_params(u32 argc, char** argv) {
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
if (getenv("AFL_LLVM_INSTRIM") != NULL || getenv("INSTRIM_LIB") != NULL)
|
||||
if (instrument_mode == INSTRUMENT_CFG)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/libLLVMInsTrim.so", obj_path);
|
||||
else
|
||||
@ -241,16 +314,12 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^USE_TRACE_PC */
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Qunused-arguments";
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
|
||||
if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;
|
||||
|
||||
while (--argc) {
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
@ -261,16 +330,11 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
if (!strcmp(cur, "-x")) x_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E"))
|
||||
maybe_linking = 0;
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
|
||||
asan_set = 1;
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
||||
|
||||
if (!strcmp(cur, "-shared")) maybe_linking = 0;
|
||||
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
|
||||
continue;
|
||||
|
||||
@ -320,20 +384,29 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_TRACE_PC
|
||||
if (getenv("AFL_USE_CFISAN")) {
|
||||
|
||||
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
|
||||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC"))
|
||||
if (getenv("AFL_INST_RATIO"))
|
||||
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
|
||||
if (instrument_mode != INSTRUMENT_LTO) {
|
||||
|
||||
#endif /* USE_TRACE_PC */
|
||||
uint32_t i = 0, found = 0;
|
||||
while (envp[i] != NULL && !found)
|
||||
if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
|
||||
if (!found) cc_params[cc_par_cnt++] = "-flto";
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=cfi";
|
||||
cc_params[cc_par_cnt++] = "-fvisibility=hidden";
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-g";
|
||||
cc_params[cc_par_cnt++] = "-O3";
|
||||
cc_params[cc_par_cnt++] = "-funroll-loops";
|
||||
if (strlen(march_opt) > 1 && march_opt[0] == '-')
|
||||
cc_params[cc_par_cnt++] = march_opt;
|
||||
|
||||
}
|
||||
|
||||
@ -406,8 +479,6 @@ static void edit_params(u32 argc, char** argv) {
|
||||
#endif /* ^__APPLE__ */
|
||||
"_I(); } while (0)";
|
||||
|
||||
if (maybe_linking) {
|
||||
|
||||
if (x_set) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-x";
|
||||
@ -442,8 +513,6 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
|
||||
}
|
||||
@ -452,25 +521,162 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
|
||||
int i;
|
||||
char *callname = "afl-clang-fast", *ptr;
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
debug = 1;
|
||||
if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
|
||||
|
||||
} else if (getenv("AFL_QUIET"))
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
#ifdef USE_TRACE_PC
|
||||
printf(
|
||||
cCYA
|
||||
"afl-clang-fast" VERSION cRST
|
||||
" [tpcg] by <lszekeres@google.com>\n"
|
||||
#else
|
||||
printf(
|
||||
cCYA
|
||||
"afl-clang-fast" VERSION cRST
|
||||
" by <lszekeres@google.com>\n"
|
||||
#endif /* ^USE_TRACE_PC */
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
#endif
|
||||
|
||||
if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) {
|
||||
|
||||
if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
|
||||
strncasecmp(ptr, "instrim", strlen("instrim")) == 0)
|
||||
instrument_mode = INSTRUMENT_CFG;
|
||||
else if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
|
||||
strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0)
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
else if (strncasecmp(ptr, "lto", strlen("lto")) == 0)
|
||||
instrument_mode = INSTRUMENT_LTO;
|
||||
else if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) {
|
||||
|
||||
instrument_mode = INSTRUMENT_CTX;
|
||||
setenv("AFL_LLVM_CTX", "1", 1);
|
||||
|
||||
} else if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) {
|
||||
|
||||
ptr += strlen("ngram");
|
||||
while (*ptr && (*ptr < '0' || *ptr > '9'))
|
||||
ptr++;
|
||||
if (!*ptr)
|
||||
if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL)
|
||||
FATAL(
|
||||
"you must set the NGRAM size with (e.g. for value 2) "
|
||||
"AFL_LLVM_INSTRUMENT=ngram-2");
|
||||
instrument_mode = INSTRUMENT_NGRAM + atoi(ptr);
|
||||
if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
|
||||
instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
|
||||
FATAL(
|
||||
"NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
|
||||
"(%u)",
|
||||
NGRAM_SIZE_MAX);
|
||||
|
||||
ptr = alloc_printf("%u", instrument_mode - INSTRUMENT_NGRAM);
|
||||
setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1);
|
||||
|
||||
} else if (strncasecmp(ptr, "classic", strlen("classic")) != 0 ||
|
||||
|
||||
strncasecmp(ptr, "default", strlen("default")) != 0 ||
|
||||
strncasecmp(ptr, "afl", strlen("afl")) != 0)
|
||||
FATAL("unknown AFL_LLVM_INSTRUMENT value: %s", ptr);
|
||||
|
||||
}
|
||||
|
||||
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
|
||||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
|
||||
|
||||
if (instrument_mode == 0)
|
||||
instrument_mode = INSTRUMENT_PCGUARD;
|
||||
else if (instrument_mode != INSTRUMENT_PCGUARD)
|
||||
FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
|
||||
getenv("INSTRIM_LIB")) {
|
||||
|
||||
if (instrument_mode == 0)
|
||||
instrument_mode = INSTRUMENT_CFG;
|
||||
else if (instrument_mode != INSTRUMENT_CFG)
|
||||
FATAL(
|
||||
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_CTX")) {
|
||||
|
||||
if (instrument_mode == 0)
|
||||
instrument_mode = INSTRUMENT_CTX;
|
||||
else if (instrument_mode != INSTRUMENT_CTX)
|
||||
FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_CTX together");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_NGRAM_SIZE")) {
|
||||
|
||||
if (instrument_mode == 0) {
|
||||
|
||||
instrument_mode = INSTRUMENT_NGRAM + atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
|
||||
if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
|
||||
instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
|
||||
FATAL(
|
||||
"NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
|
||||
"(%u)",
|
||||
NGRAM_SIZE_MAX);
|
||||
|
||||
} else if (instrument_mode != INSTRUMENT_NGRAM)
|
||||
|
||||
FATAL(
|
||||
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_NGRAM_SIZE "
|
||||
"together");
|
||||
|
||||
}
|
||||
|
||||
if (instrument_mode < INSTRUMENT_NGRAM)
|
||||
ptr = instrument_mode_string[instrument_mode];
|
||||
else
|
||||
ptr = alloc_printf("NGRAM-%u", instrument_mode - INSTRUMENT_NGRAM);
|
||||
|
||||
if (strstr(argv[0], "afl-clang-lto") != NULL) {
|
||||
|
||||
if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO) {
|
||||
|
||||
callname = "afl-clang-lto";
|
||||
instrument_mode = INSTRUMENT_LTO;
|
||||
ptr = instrument_mode_string[instrument_mode];
|
||||
|
||||
} else {
|
||||
|
||||
if (!be_quiet)
|
||||
WARNF("afl-clang-lto called with mode %s, using that mode instead",
|
||||
ptr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifndef AFL_CLANG_FLTO
|
||||
if (instrument_mode == INSTRUMENT_LTO)
|
||||
FATAL("instrumentation mode LTO specified but LLVM support not available");
|
||||
#endif
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
|
||||
|
||||
if (instrument_mode != INSTRUMENT_LTO)
|
||||
printf("afl-clang-fast" VERSION " by <lszekeres@google.com> in %s mode\n",
|
||||
ptr);
|
||||
else
|
||||
printf("afl-clang-lto" VERSION
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in %s mode\n",
|
||||
ptr);
|
||||
|
||||
SAYF(
|
||||
"\n"
|
||||
"afl-clang-fast[++] [options]\n"
|
||||
"%s[++] [options]\n"
|
||||
"\n"
|
||||
"This is a helper application for afl-fuzz. It serves as a drop-in "
|
||||
"replacement\n"
|
||||
"for clang, letting you recompile third-party code with the required "
|
||||
"for clang, letting you recompile third-party code with the "
|
||||
"required "
|
||||
"runtime\n"
|
||||
"instrumentation. A common use pattern would be one of the "
|
||||
"following:\n\n"
|
||||
@ -483,48 +689,120 @@ int main(int argc, char** argv, char** envp) {
|
||||
"an LLVM pass and tends to offer improved performance with slow "
|
||||
"programs.\n\n"
|
||||
|
||||
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
|
||||
"Setting\n"
|
||||
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n"
|
||||
"afl-clang-fast was built for llvm %s with the llvm binary path of "
|
||||
"\"%s\".\n\n",
|
||||
BIN_PATH, BIN_PATH, LLVM_VERSION, LLVM_BINDIR);
|
||||
"Environment variables used:\n"
|
||||
"AFL_CC: path to the C compiler to use\n"
|
||||
"AFL_CXX: path to the C++ compiler to use\n"
|
||||
"AFL_PATH: path to instrumenting pass and runtime "
|
||||
"(afl-llvm-rt.*o)\n"
|
||||
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_INST_RATIO: percentage of branches to instrument\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_DEBUG: enable developer debugging output\n"
|
||||
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_MSAN: activate memory sanitizer\n"
|
||||
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
|
||||
"AFL_USE_CFISAN: activate control flow sanitizer\n"
|
||||
"AFL_LLVM_WHITELIST: enable whitelisting (selective "
|
||||
"instrumentation)\n"
|
||||
"AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
|
||||
"AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
|
||||
"AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
|
||||
"function calls\n"
|
||||
" to cascaded comparisons\n"
|
||||
"AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to "
|
||||
"cascaded "
|
||||
"comp.\n"
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n",
|
||||
callname, BIN_PATH, BIN_PATH);
|
||||
|
||||
SAYF(
|
||||
"\nafl-clang-fast specific environment variables:\n"
|
||||
"AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
|
||||
"AFL_LLVM_INSTRUMENT: set instrumentation mode: DEFAULT, CFG "
|
||||
"(INSTRIM), LTO, CTX, NGRAM-2 ... NGRAM-16\n"
|
||||
"You can also use the old environment variables:"
|
||||
"AFL_LLVM_CTX: use context sensitive coverage\n"
|
||||
"AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
|
||||
"AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n"
|
||||
"AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub "
|
||||
"option to INSTRIM)\n");
|
||||
|
||||
#ifdef AFL_CLANG_FLTO
|
||||
SAYF(
|
||||
"\nafl-clang-lto specific environment variables:\n"
|
||||
"AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
|
||||
"bb\n"
|
||||
"AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
|
||||
"global var\n"
|
||||
"AFL_REAL_LD: use this linker instead of the compiled in path\n"
|
||||
"AFL_LD_PASSTHROUGH: do not perform instrumentation (for configure "
|
||||
"scripts)\n"
|
||||
"\nafl-clang-lto was built with linker target \"%s\" and LTO flags "
|
||||
"\"%s\"\n"
|
||||
"If anything fails - be sure to read README.lto.md!\n",
|
||||
AFL_REAL_LD, AFL_CLANG_FLTO);
|
||||
#endif
|
||||
|
||||
SAYF(
|
||||
"\nafl-clang-fast was built for llvm %s with the llvm binary path "
|
||||
"of \"%s\".\n",
|
||||
LLVM_VERSION, LLVM_BINDIR);
|
||||
|
||||
SAYF("\n");
|
||||
|
||||
exit(1);
|
||||
|
||||
} else if ((isatty(2) && !getenv("AFL_QUIET")) ||
|
||||
} else if ((isatty(2) && !be_quiet) ||
|
||||
|
||||
getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
#ifdef USE_TRACE_PC
|
||||
if (instrument_mode != INSTRUMENT_LTO)
|
||||
|
||||
SAYF(cCYA "afl-clang-fast" VERSION cRST
|
||||
" [tpcg] by <lszekeres@google.com>\n");
|
||||
#warning \
|
||||
"You do not need to specifically compile with USE_TRACE_PC anymore, setting the environment variable AFL_LLVM_USE_TRACE_PC is enough."
|
||||
#else
|
||||
SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n");
|
||||
#endif /* ^USE_TRACE_PC */
|
||||
" by <lszekeres@google.com> in %s mode\n",
|
||||
ptr);
|
||||
|
||||
else
|
||||
|
||||
SAYF(cCYA "afl-clang-lto" VERSION cRST
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in mode %s\n",
|
||||
ptr);
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < argc; i++)
|
||||
SAYF(" \"%s\"", argv[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
check_environment_vars(envp);
|
||||
|
||||
cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG");
|
||||
if (cmplog_mode) printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
|
||||
if (!be_quiet && cmplog_mode)
|
||||
printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
|
||||
|
||||
#ifndef __ANDROID__
|
||||
find_obj(argv[0]);
|
||||
#endif
|
||||
|
||||
edit_params(argc, argv);
|
||||
edit_params(argc, argv, envp);
|
||||
|
||||
/*
|
||||
int i = 0;
|
||||
printf("EXEC:");
|
||||
while (cc_params[i] != NULL)
|
||||
printf(" %s", cc_params[i++]);
|
||||
printf("\n");
|
||||
*/
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < cc_par_cnt; i++)
|
||||
SAYF(" \"%s\"", cc_params[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
|
||||
|
839
llvm_mode/afl-ld.c
Normal file
839
llvm_mode/afl-ld.c
Normal file
@ -0,0 +1,839 @@
|
||||
/*
|
||||
american fuzzy lop++ - wrapper for GNU ld
|
||||
-----------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de> for afl++
|
||||
|
||||
Maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Dominik Maier <domenukk@gmail.com>
|
||||
|
||||
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
|
||||
|
||||
The sole purpose of this wrapper is to preprocess clang LTO files before
|
||||
linking by ld and perform the instrumentation on the whole program.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define MAX_PARAM_COUNT 4096
|
||||
|
||||
static u8 **ld_params, /* Parameters passed to the real 'ld' */
|
||||
**link_params, /* Parameters passed to 'llvm-link' */
|
||||
**opt_params, /* Parameters passed to 'opt' opt */
|
||||
**inst_params; /* Parameters passed to 'opt' inst */
|
||||
|
||||
static u8 *input_file; /* Originally specified input file */
|
||||
static u8 *final_file, /* Instrumented file for the real 'ld' */
|
||||
*linked_file, /* file where we link all files */
|
||||
*modified_file; /* file that was optimized before instr */
|
||||
static u8 *afl_path = AFL_PATH;
|
||||
static u8 *real_ld = AFL_REAL_LD;
|
||||
static u8 cwd[4096];
|
||||
static u8 *tmp_dir;
|
||||
static u8 *ar_dir;
|
||||
static u8 ar_dir_cnt;
|
||||
static u8 *libdirs[254];
|
||||
static u8 libdir_cnt;
|
||||
|
||||
static u8 be_quiet, /* Quiet mode (no stderr output) */
|
||||
debug, /* AFL_DEBUG */
|
||||
passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/
|
||||
we_link, /* we have bc/ll -> link + optimize */
|
||||
just_version; /* Just show version? */
|
||||
|
||||
static u32 ld_param_cnt = 1, /* Number of params to 'ld' */
|
||||
link_param_cnt = 1, /* Number of params to 'llvm-link' */
|
||||
opt_param_cnt = 1, /* Number of params to 'opt' opt */
|
||||
inst_param_cnt = 1; /* Number of params to 'opt' instr */
|
||||
|
||||
/* This function wipes a directory - our AR unpack directory in this case */
|
||||
static u8 wipe_directory(u8 *path) {
|
||||
|
||||
DIR * d;
|
||||
struct dirent *d_ent;
|
||||
|
||||
d = opendir(path);
|
||||
|
||||
if (!d) return 0;
|
||||
|
||||
while ((d_ent = readdir(d))) {
|
||||
|
||||
if (strcmp(d_ent->d_name, ".") != 0 && strcmp(d_ent->d_name, "..") != 0) {
|
||||
|
||||
u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
|
||||
if (unlink(fname)) PFATAL("Unable to delete '%s'", fname);
|
||||
ck_free(fname);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
return !!rmdir(path);
|
||||
|
||||
}
|
||||
|
||||
/* remove temporary files on fatal errors */
|
||||
static void at_exit_handler(void) {
|
||||
|
||||
if (!getenv("AFL_KEEP_ASSEMBLY")) {
|
||||
|
||||
if (linked_file) {
|
||||
|
||||
unlink(linked_file);
|
||||
linked_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (modified_file) {
|
||||
|
||||
unlink(modified_file);
|
||||
modified_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (final_file) {
|
||||
|
||||
unlink(final_file);
|
||||
final_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (ar_dir != NULL) {
|
||||
|
||||
wipe_directory(ar_dir);
|
||||
ar_dir = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This function checks if the parameter is a) an existing file and b)
|
||||
if it is a BC or LL file, if both are true it returns 1 and 0 otherwise */
|
||||
int is_llvm_file(const char *file) {
|
||||
|
||||
int fd;
|
||||
u8 buf[5];
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||
|
||||
if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (read(fd, buf, 4) != 4) return 0;
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
if (strncmp(buf, "; Mo", 4) == 0) return 1;
|
||||
|
||||
if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Return the current working directory, not thread safe ;-) */
|
||||
u8 *getthecwd() {
|
||||
|
||||
static u8 fail[] = "";
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) return fail;
|
||||
return cwd;
|
||||
|
||||
}
|
||||
|
||||
/* Check if an ar extracted file is already in the parameter list */
|
||||
int is_duplicate(u8 **params, u32 ld_param_cnt, u8 *ar_file) {
|
||||
|
||||
for (uint32_t i = 0; i < ld_param_cnt; i++)
|
||||
if (params[i] != NULL)
|
||||
if (strcmp(params[i], ar_file) == 0) return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
|
||||
Note that the file name is always the last parameter passed by GCC,
|
||||
so we exploit this property to keep the code "simple". */
|
||||
static void edit_params(int argc, char **argv) {
|
||||
|
||||
u32 i, have_lto = 0, libdir_index;
|
||||
u8 libdir_file[4096];
|
||||
|
||||
if (tmp_dir == NULL) {
|
||||
|
||||
tmp_dir = getenv("TMPDIR");
|
||||
if (!tmp_dir) tmp_dir = getenv("TEMP");
|
||||
if (!tmp_dir) tmp_dir = getenv("TMP");
|
||||
if (!tmp_dir) tmp_dir = "/tmp";
|
||||
|
||||
}
|
||||
|
||||
linked_file =
|
||||
alloc_printf("%s/.afl-%u-%u-1.ll", tmp_dir, getpid(), (u32)time(NULL));
|
||||
modified_file =
|
||||
alloc_printf("%s/.afl-%u-%u-2.bc", tmp_dir, getpid(), (u32)time(NULL));
|
||||
final_file =
|
||||
alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL));
|
||||
|
||||
ld_params = ck_alloc(4096 * sizeof(u8 *));
|
||||
link_params = ck_alloc(4096 * sizeof(u8 *));
|
||||
inst_params = ck_alloc(12 * sizeof(u8 *));
|
||||
opt_params = ck_alloc(12 * sizeof(u8 *));
|
||||
|
||||
ld_params[0] = (u8 *)real_ld;
|
||||
ld_params[ld_param_cnt++] = "--allow-multiple-definition";
|
||||
|
||||
link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link");
|
||||
link_params[link_param_cnt++] = "-S"; // we create the linked file as .ll
|
||||
link_params[link_param_cnt++] = "-o";
|
||||
link_params[link_param_cnt++] = linked_file;
|
||||
|
||||
opt_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
|
||||
if (getenv("AFL_DONT_OPTIMIZE") == NULL)
|
||||
opt_params[opt_param_cnt++] = "-O3";
|
||||
else
|
||||
opt_params[opt_param_cnt++] = "-O0";
|
||||
|
||||
// opt_params[opt_param_cnt++] = "-S"; // only when debugging
|
||||
opt_params[opt_param_cnt++] = linked_file; // input: .ll file
|
||||
opt_params[opt_param_cnt++] = "-o";
|
||||
opt_params[opt_param_cnt++] = modified_file; // output: .bc file
|
||||
|
||||
inst_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
|
||||
inst_params[inst_param_cnt++] =
|
||||
alloc_printf("--load=%s/afl-llvm-lto-instrumentation.so", afl_path);
|
||||
// inst_params[inst_param_cnt++] = "-S"; // only when debugging
|
||||
inst_params[inst_param_cnt++] = "--disable-opt";
|
||||
inst_params[inst_param_cnt++] = "--afl-lto";
|
||||
inst_params[inst_param_cnt++] = modified_file; // input: .bc file
|
||||
inst_params[inst_param_cnt++] = "-o";
|
||||
inst_params[inst_param_cnt++] = final_file; // output: .bc file
|
||||
|
||||
// first we must collect all library search paths
|
||||
for (i = 1; i < argc; i++)
|
||||
if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L')
|
||||
libdirs[libdir_cnt++] = argv[i] + 2;
|
||||
|
||||
// then we inspect all options to the target linker
|
||||
for (i = 1; i < argc; i++) {
|
||||
|
||||
if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT)
|
||||
FATAL(
|
||||
"Too many command line parameters because of unpacking .a archives, "
|
||||
"this would need to be done by hand ... sorry! :-(");
|
||||
|
||||
if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1;
|
||||
|
||||
if (!strcmp(argv[i], "-version")) {
|
||||
|
||||
just_version = 1;
|
||||
ld_params[1] = argv[i];
|
||||
ld_params[2] = NULL;
|
||||
final_file = input_file;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "--afl") == 0) {
|
||||
|
||||
if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
// if a -l library is linked and no .so is found but an .a archive is there
|
||||
// then the archive will be used. So we have to emulate this and check
|
||||
// if an archive will be used and if yes we will instrument it too
|
||||
libdir_file[0] = 0;
|
||||
libdir_index = libdir_cnt;
|
||||
if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 &&
|
||||
strncmp(argv[i], "-lgcc", 5) != 0) {
|
||||
|
||||
u8 found = 0;
|
||||
|
||||
for (uint32_t j = 0; j < libdir_cnt && !found; j++) {
|
||||
|
||||
snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
|
||||
argv[i] + 2, ".so");
|
||||
if (access(libdir_file, R_OK) != 0) { // no .so found?
|
||||
|
||||
snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
|
||||
argv[i] + 2, ".a");
|
||||
if (access(libdir_file, R_OK) == 0) { // but .a found?
|
||||
|
||||
libdir_index = j;
|
||||
found = 1;
|
||||
if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
found = 1;
|
||||
if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// is the parameter an .a AR archive? If so, unpack and check its files
|
||||
if (libdir_index < libdir_cnt ||
|
||||
(argv[i][0] != '-' && strlen(argv[i]) > 2 &&
|
||||
argv[i][strlen(argv[i]) - 1] == 'a' &&
|
||||
argv[i][strlen(argv[i]) - 2] == '.')) {
|
||||
|
||||
// This gets a bit odd. I encountered several .a files being linked and
|
||||
// where the same "foo.o" was in both .a archives. llvm-link does not
|
||||
// like this so we have to work around that ...
|
||||
|
||||
u8 this_wd[4096], *this_ar;
|
||||
u8 ar_params_cnt = 4;
|
||||
u8 * ar_params[ar_params_cnt];
|
||||
u8 * file = argv[i];
|
||||
s32 pid, status;
|
||||
DIR * arx;
|
||||
struct dirent *dir_ent;
|
||||
|
||||
if (libdir_index < libdir_cnt) file = libdir_file;
|
||||
|
||||
if (ar_dir_cnt == 0) { // first archive, we setup up the basics
|
||||
|
||||
ar_dir = alloc_printf("%s/.afl-%u-%u.dir", tmp_dir, getpid(),
|
||||
(u32)time(NULL));
|
||||
if (mkdir(ar_dir, 0700) != 0)
|
||||
FATAL("can not create temporary directory %s", ar_dir);
|
||||
|
||||
}
|
||||
|
||||
if (getcwd(this_wd, sizeof(this_wd)) == NULL)
|
||||
FATAL("can not get the current working directory");
|
||||
if (chdir(ar_dir) != 0)
|
||||
FATAL("can not chdir to temporary directory %s", ar_dir);
|
||||
if (file[0] == '/')
|
||||
this_ar = file;
|
||||
else
|
||||
this_ar = alloc_printf("%s/%s", this_wd, file);
|
||||
ar_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-ar");
|
||||
ar_params[1] = "x";
|
||||
ar_params[2] = this_ar;
|
||||
ar_params[3] = NULL;
|
||||
|
||||
if (!be_quiet) OKF("Running ar unpacker on %s into %s", this_ar, ar_dir);
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (uint32_t j = 0; j < ar_params_cnt; j++)
|
||||
SAYF(" \"%s\"", ar_params[j]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
if (!(pid = fork())) {
|
||||
|
||||
execvp(ar_params[0], (char **)ar_params);
|
||||
FATAL("Oops, failed to execute '%s'", ar_params[0]);
|
||||
|
||||
}
|
||||
|
||||
if (pid < 0) FATAL("fork() failed");
|
||||
if (waitpid(pid, &status, 0) <= 0) FATAL("waitpid() failed");
|
||||
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
|
||||
|
||||
if (chdir(this_wd) != 0)
|
||||
FATAL("can not chdir back to our working directory %s", this_wd);
|
||||
|
||||
if (!(arx = opendir(ar_dir))) FATAL("can not open directory %s", ar_dir);
|
||||
|
||||
while ((dir_ent = readdir(arx)) != NULL) {
|
||||
|
||||
u8 *ar_file = alloc_printf("%s/%s", ar_dir, dir_ent->d_name);
|
||||
|
||||
if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' &&
|
||||
dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') {
|
||||
|
||||
if (passthrough || is_llvm_file(ar_file) == 0) {
|
||||
|
||||
if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) {
|
||||
|
||||
ld_params[ld_param_cnt++] = ar_file;
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "not a LTO link file: %s\n", ar_file);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (is_duplicate(link_params, link_param_cnt, ar_file) == 0) {
|
||||
|
||||
if (we_link == 0) { // we have to honor order ...
|
||||
|
||||
ld_params[ld_param_cnt++] = final_file;
|
||||
we_link = 1;
|
||||
|
||||
}
|
||||
|
||||
link_params[link_param_cnt++] = ar_file;
|
||||
if (debug) SAYF(cMGN "[D] " cRST "is a link file: %s\n", ar_file);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
if (dir_ent->d_name[0] != '.' && !be_quiet)
|
||||
WARNF("Unusual file found in ar archive %s: %s", argv[i], ar_file);
|
||||
|
||||
}
|
||||
|
||||
closedir(arx);
|
||||
ar_dir_cnt++;
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (passthrough || argv[i][0] == '-' || is_llvm_file(argv[i]) == 0) {
|
||||
|
||||
// -O3 fucks up the CFG and instrumentation, so we downgrade to O2
|
||||
// which is as we want things. Lets hope this is not too different
|
||||
// in the various llvm versions!
|
||||
if (strncmp(argv[i], "-plugin-opt=O", 13) == 0 &&
|
||||
!getenv("AFL_DONT_OPTIMIZE"))
|
||||
ld_params[ld_param_cnt++] = "-plugin-opt=O2";
|
||||
else
|
||||
ld_params[ld_param_cnt++] = argv[i];
|
||||
|
||||
} else {
|
||||
|
||||
if (we_link == 0) { // we have to honor order ...
|
||||
ld_params[ld_param_cnt++] = final_file;
|
||||
we_link = 1;
|
||||
|
||||
}
|
||||
|
||||
link_params[link_param_cnt++] = argv[i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if (have_lto == 0) ld_params[ld_param_cnt++] = AFL_CLANG_FLTO; // maybe we
|
||||
// should not ...
|
||||
ld_params[ld_param_cnt] = NULL;
|
||||
link_params[link_param_cnt] = NULL;
|
||||
opt_params[opt_param_cnt] = NULL;
|
||||
inst_params[inst_param_cnt] = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* clean AFL_PATH from PATH */
|
||||
|
||||
void clean_path() {
|
||||
|
||||
char *tmp, *newpath = NULL, *path = getenv("PATH");
|
||||
u8 done = 0;
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D]" cRST " old PATH=%s, AFL_PATH=%s\n", path, AFL_PATH);
|
||||
|
||||
// wipe AFL paths from PATH that we set
|
||||
// we added two paths so we remove the two paths
|
||||
while (!done) {
|
||||
|
||||
if (*path == 0)
|
||||
done = 1;
|
||||
else if (*path++ == ':')
|
||||
done = 1;
|
||||
|
||||
}
|
||||
|
||||
while (*path == ':')
|
||||
path++;
|
||||
|
||||
// AFL_PATH could be additionally in PATH so check and remove to not call our
|
||||
// 'ld'
|
||||
const size_t pathlen = strlen(path);
|
||||
const size_t afl_pathlen = strlen(AFL_PATH);
|
||||
newpath = malloc(pathlen + 1);
|
||||
if (strcmp(AFL_PATH, "/bin") != 0 && strcmp(AFL_PATH, "/usr/bin") != 0 &&
|
||||
afl_pathlen > 1 && (tmp = strstr(path, AFL_PATH)) != NULL && // it exists
|
||||
(tmp == path ||
|
||||
(tmp > path &&
|
||||
tmp[-1] == ':')) && // either starts with it or has a colon before
|
||||
(tmp + afl_pathlen == path + pathlen ||
|
||||
(tmp + afl_pathlen <
|
||||
path + (pathlen && tmp[afl_pathlen] ==
|
||||
':')) // end with it or has a colon at the end
|
||||
)) {
|
||||
|
||||
int one_colon = 1;
|
||||
|
||||
if (tmp > path) {
|
||||
|
||||
memcpy(newpath, path, tmp - path);
|
||||
newpath[tmp - path - 1] = 0; // remove ':'
|
||||
one_colon = 0;
|
||||
|
||||
}
|
||||
|
||||
if (tmp + afl_pathlen < path + pathlen) tmp += afl_pathlen + one_colon;
|
||||
|
||||
setenv("PATH", newpath, 1);
|
||||
|
||||
} else
|
||||
|
||||
setenv("PATH", path, 1);
|
||||
|
||||
if (debug) SAYF(cMGN "[D]" cRST " new PATH=%s\n", getenv("PATH"));
|
||||
free(newpath);
|
||||
|
||||
}
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
s32 pid, i;
|
||||
int status;
|
||||
u8 *ptr, exe[4096], exe2[4096], proc[32], val[2] = " ";
|
||||
int have_afl_ld_caller = 0;
|
||||
|
||||
if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
|
||||
|
||||
if (getenv("AFL_LD") != NULL)
|
||||
SAYF(cCYA "afl-ld" VERSION cRST
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> (level %d)\n",
|
||||
have_afl_ld_caller);
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG") != NULL) debug = 1;
|
||||
if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
|
||||
if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
|
||||
if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
|
||||
if (real_ld == NULL || strlen(real_ld) < 2) real_ld = "/bin/ld";
|
||||
if (real_ld != NULL && real_ld[0] != '/')
|
||||
real_ld = alloc_printf("/bin/%s", real_ld);
|
||||
|
||||
if ((ptr = getenv("AFL_LD_CALLER")) != NULL) have_afl_ld_caller = atoi(ptr);
|
||||
val[0] = 0x31 + have_afl_ld_caller;
|
||||
setenv("AFL_LD_CALLER", val, 1);
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"AFL_LD=%s, set AFL_LD_CALLER=%s, have_afl_ld_caller=%d, "
|
||||
"real_ld=%s\n",
|
||||
getenv("AFL_LD"), val, have_afl_ld_caller, real_ld);
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < argc; i++)
|
||||
SAYF(" \"%s\"", argv[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
sprintf(proc, "/proc/%d/exe", getpid());
|
||||
if (readlink(proc, exe, sizeof(exe) - 1) > 0) {
|
||||
|
||||
if (readlink(real_ld, exe2, sizeof(exe2) - 1) < 1) exe2[0] = 0;
|
||||
exe[sizeof(exe) - 1] = 0;
|
||||
exe[sizeof(exe2) - 1] = 0;
|
||||
if (strcmp(exe, real_ld) == 0 || strcmp(exe, exe2) == 0)
|
||||
PFATAL(cLRD "[!] " cRST
|
||||
"Error: real 'ld' path points to afl-ld, set AFL_REAL_LD to "
|
||||
"the real 'ld' program!");
|
||||
|
||||
}
|
||||
|
||||
if (have_afl_ld_caller > 1)
|
||||
PFATAL(cLRD "[!] " cRST
|
||||
"Error: afl-ld calls itself in a loop, set AFL_REAL_LD to the "
|
||||
"real 'ld' program!");
|
||||
|
||||
if (argc < 2) {
|
||||
|
||||
SAYF(
|
||||
"\n"
|
||||
"This is a helper application for afl-fuzz. It is a wrapper around GNU "
|
||||
"'ld',\n"
|
||||
"executed by the toolchain whenever using "
|
||||
"afl-clang-lto/afl-clang-lto++.\n"
|
||||
"You probably don't want to run this program directly.\n\n"
|
||||
|
||||
"Environment variables:\n"
|
||||
" AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n"
|
||||
" AFL_REAL_LD point to the real ld if necessary\n"
|
||||
|
||||
"\nafl-ld was compiled with the fixed real 'ld' path of %s and the "
|
||||
"clang "
|
||||
"bin path of %s\n\n",
|
||||
real_ld, LLVM_BINDIR);
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LD") == NULL) {
|
||||
|
||||
/* if someone install clang/ld into the same directory as afl++ then
|
||||
they are out of luck ... */
|
||||
|
||||
if (have_afl_ld_caller == 1) { clean_path(); }
|
||||
|
||||
if (real_ld != NULL && strlen(real_ld) > 1) execvp(real_ld, argv);
|
||||
execvp("ld", argv); // fallback
|
||||
PFATAL("Oops, failed to execute 'ld' - check your PATH");
|
||||
|
||||
}
|
||||
|
||||
atexit(at_exit_handler); // ensure to wipe temp files if things fail
|
||||
|
||||
edit_params(argc, argv); // here most of the magic happens :-)
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST
|
||||
"param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n",
|
||||
ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt,
|
||||
inst_param_cnt);
|
||||
|
||||
if (!just_version) {
|
||||
|
||||
if (we_link == 0) {
|
||||
|
||||
if (!getenv("AFL_QUIET"))
|
||||
WARNF("No LTO input file found, cannot instrument!");
|
||||
|
||||
} else {
|
||||
|
||||
/* first we link all files */
|
||||
if (!be_quiet) OKF("Running bitcode linker, creating %s", linked_file);
|
||||
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < link_param_cnt; i++)
|
||||
SAYF(" \"%s\"", link_params[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
if (!(pid = fork())) {
|
||||
|
||||
execvp(link_params[0], (char **)link_params);
|
||||
FATAL("Oops, failed to execute '%s'", link_params[0]);
|
||||
|
||||
}
|
||||
|
||||
if (pid < 0) PFATAL("fork() failed");
|
||||
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD
|
||||
"\n[-] PROGRAM ABORT : " cRST);
|
||||
SAYF(
|
||||
"llvm-link failed! Probable causes:\n\n"
|
||||
" #1 If the error is \"linking globals named '...': symbol "
|
||||
"multiply defined\"\n"
|
||||
" then there is nothing we can do - llvm-link is missing an "
|
||||
"important feature\n\n"
|
||||
" #2 If the error is \"expected top-level entity\" and then "
|
||||
"binary output, this\n"
|
||||
" is because the same file is present in different .a archives "
|
||||
"in different\n"
|
||||
" formats. This can be fixed by manual doing the steps afl-ld "
|
||||
"is doing but\n"
|
||||
" programmatically - sorry!\n\n");
|
||||
exit(WEXITSTATUS(status));
|
||||
|
||||
}
|
||||
|
||||
/* then we perform an optimization on the collected objects files */
|
||||
if (!be_quiet)
|
||||
OKF("Performing optimization via opt, creating %s", modified_file);
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < opt_param_cnt; i++)
|
||||
SAYF(" \"%s\"", opt_params[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
if (!(pid = fork())) {
|
||||
|
||||
execvp(opt_params[0], (char **)opt_params);
|
||||
FATAL("Oops, failed to execute '%s'", opt_params[0]);
|
||||
|
||||
}
|
||||
|
||||
if (pid < 0) PFATAL("fork() failed");
|
||||
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
|
||||
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
|
||||
|
||||
/* then we run the instrumentation through the optimizer */
|
||||
if (!be_quiet)
|
||||
OKF("Performing instrumentation via opt, creating %s", final_file);
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < inst_param_cnt; i++)
|
||||
SAYF(" \"%s\"", inst_params[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
if (!(pid = fork())) {
|
||||
|
||||
execvp(inst_params[0], (char **)inst_params);
|
||||
FATAL("Oops, failed to execute '%s'", inst_params[0]);
|
||||
|
||||
}
|
||||
|
||||
if (pid < 0) PFATAL("fork() failed");
|
||||
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
|
||||
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
|
||||
|
||||
}
|
||||
|
||||
/* next step - run the linker! :-) */
|
||||
|
||||
}
|
||||
|
||||
if (!be_quiet) OKF("Running real linker %s", real_ld);
|
||||
if (debug) {
|
||||
|
||||
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
|
||||
for (i = 0; i < ld_param_cnt; i++)
|
||||
SAYF(" \"%s\"", ld_params[i]);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
if (!(pid = fork())) {
|
||||
|
||||
clean_path();
|
||||
|
||||
unsetenv("AFL_LD");
|
||||
|
||||
if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
|
||||
execvp("ld", (char **)ld_params); // fallback
|
||||
FATAL("Oops, failed to execute 'ld' - check your PATH");
|
||||
|
||||
}
|
||||
|
||||
if (pid < 0) PFATAL("fork() failed");
|
||||
|
||||
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
|
||||
if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
|
||||
|
||||
if (!just_version) {
|
||||
|
||||
if (!getenv("AFL_KEEP_ASSEMBLY")) {
|
||||
|
||||
if (linked_file) {
|
||||
|
||||
unlink(linked_file);
|
||||
linked_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (modified_file) {
|
||||
|
||||
unlink(modified_file);
|
||||
modified_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (final_file) {
|
||||
|
||||
unlink(final_file);
|
||||
final_file = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (ar_dir != NULL) {
|
||||
|
||||
wipe_directory(ar_dir);
|
||||
ar_dir = NULL;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
SAYF(
|
||||
"[!] afl-ld: keeping link file %s, optimized bitcode %s and "
|
||||
"instrumented bitcode %s",
|
||||
linked_file, modified_file, final_file);
|
||||
if (ar_dir_cnt > 0 && ar_dir)
|
||||
SAYF(" and ar archive unpack directory %s", ar_dir);
|
||||
SAYF("\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
|
||||
if (!be_quiet) OKF("Linker was successful");
|
||||
|
||||
} else {
|
||||
|
||||
SAYF(cLRD "[-] " cRST
|
||||
"Linker failed, please investigate and send a bug report. Most "
|
||||
"likely an 'ld' option is incompatible with %s. Try "
|
||||
"AFL_KEEP_ASSEMBLY=1 and AFL_DEBUG=1 for replaying.\n",
|
||||
AFL_CLANG_FLTO);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exit(WEXITSTATUS(status));
|
||||
|
||||
}
|
||||
|
427
llvm_mode/afl-llvm-lto-instrumentation.so.cc
Normal file
427
llvm_mode/afl-llvm-lto-instrumentation.so.cc
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM-mode instrumentation pass
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
|
||||
from afl-as.c are Michal's fault.
|
||||
|
||||
Copyright 2015, 2016 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
|
||||
|
||||
This library is plugged into LLVM when invoking clang through afl-clang-fast.
|
||||
It tells the compiler to add code roughly equivalent to the bits discussed
|
||||
in ../afl-as.h.
|
||||
|
||||
*/
|
||||
|
||||
// CONFIG OPTION:
|
||||
// If #define USE_SPLIT is used, then the llvm::SplitEdge function is used
|
||||
// instead of our own implementation. Ours looks better and will
|
||||
// compile everywhere. But it is not working for complex code. yet. damn.
|
||||
#define USE_SPLIT
|
||||
|
||||
#define AFL_LLVM_PASS
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||
typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/MemorySSAUpdater.h"
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class AFLLTOPass : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
AFLLTOPass() : ModulePass(ID) {
|
||||
|
||||
char *ptr;
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
|
||||
if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE)
|
||||
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
|
||||
ptr, MAP_SIZE - 1);
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
|
||||
ModulePass::getAnalysisUsage(AU);
|
||||
AU.addRequired<DominatorTreeWrapperPass>();
|
||||
AU.addRequired<LoopInfoWrapperPass>();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Calculate the number of average collisions that would occur if all
|
||||
// location IDs would be assigned randomly (like normal afl/afl++).
|
||||
// This uses the "balls in bins" algorithm.
|
||||
unsigned long long int calculateCollisions(uint32_t edges) {
|
||||
|
||||
double bins = MAP_SIZE;
|
||||
double balls = edges;
|
||||
double step1 = 1 - (1 / bins);
|
||||
double step2 = pow(step1, balls);
|
||||
double step3 = bins * step2;
|
||||
double step4 = round(step3);
|
||||
unsigned long long int empty = step4;
|
||||
unsigned long long int collisions = edges - (MAP_SIZE - empty);
|
||||
return collisions;
|
||||
|
||||
}
|
||||
|
||||
// Get the internal llvm name of a basic block
|
||||
// This is an ugly debug support so it is commented out :-)
|
||||
/*
|
||||
static char *getBBName(const BasicBlock *BB) {
|
||||
|
||||
static char *name;
|
||||
|
||||
if (!BB->getName().empty()) {
|
||||
|
||||
name = strdup(BB->getName().str().c_str());
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
BB->printAsOperand(OS, false);
|
||||
|
||||
name = strdup(OS.str().c_str());
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
static bool isBlacklisted(const Function *F) {
|
||||
|
||||
static const char *Blacklist[] = {
|
||||
|
||||
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign.",
|
||||
"__afl_", "_fini", "__libc_csu"
|
||||
|
||||
};
|
||||
|
||||
for (auto const &BlacklistFunc : Blacklist) {
|
||||
|
||||
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
protected:
|
||||
int afl_global_id = 1, debug = 0;
|
||||
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
u32 rand_seed;
|
||||
|
||||
/* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
|
||||
gettimeofday(&tv, &tz);
|
||||
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
|
||||
AFL_SR(rand_seed);
|
||||
|
||||
/* Show a banner */
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-lto" VERSION cRST
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
|
||||
#endif
|
||||
|
||||
/* Get globals for the SHM region and the previous location. Note that
|
||||
__afl_prev_loc is thread-local. */
|
||||
|
||||
GlobalVariable *AFLMapPtr =
|
||||
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
|
||||
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
|
||||
|
||||
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
|
||||
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
|
||||
|
||||
/* Instrument all the things! */
|
||||
|
||||
int inst_blocks = 0;
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
if (F.size() < 2) continue;
|
||||
if (isBlacklisted(&F)) continue;
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
// DominatorTree &DT =
|
||||
// getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); LoopInfo & LI =
|
||||
// getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
|
||||
#endif
|
||||
|
||||
std::vector<BasicBlock *> InsBlocks;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
uint32_t succ = 0;
|
||||
|
||||
for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB); SI != SE;
|
||||
++SI)
|
||||
if ((*SI)->size() > 0) succ++;
|
||||
|
||||
if (succ < 2) // no need to instrument
|
||||
continue;
|
||||
|
||||
InsBlocks.push_back(&BB);
|
||||
|
||||
}
|
||||
|
||||
if (InsBlocks.size() > 0) {
|
||||
|
||||
uint32_t i = InsBlocks.size();
|
||||
|
||||
do {
|
||||
|
||||
--i;
|
||||
BasicBlock * origBB = &(*InsBlocks[i]);
|
||||
std::vector<BasicBlock *> Successors;
|
||||
Instruction * TI = origBB->getTerminator();
|
||||
|
||||
for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
|
||||
SI != SE; ++SI) {
|
||||
|
||||
BasicBlock *succ = *SI;
|
||||
Successors.push_back(succ);
|
||||
|
||||
}
|
||||
|
||||
if (TI == NULL || TI->getNumSuccessors() < 2) continue;
|
||||
|
||||
// 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++) {
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
BasicBlock *newBB = llvm::SplitEdge(origBB, Successors[j]);
|
||||
#else
|
||||
BasicBlock *newBB = BasicBlock::Create(C, "", &F, nullptr);
|
||||
#endif
|
||||
|
||||
if (!newBB) {
|
||||
|
||||
if (!be_quiet) WARNF("Split failed!");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
BasicBlock::iterator IP = newBB->getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
#else
|
||||
IRBuilder<> IRB(&(*newBB));
|
||||
#endif
|
||||
|
||||
/* Set the ID of the inserted basic block */
|
||||
|
||||
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, afl_global_id++);
|
||||
|
||||
/* Load SHM pointer */
|
||||
|
||||
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
|
||||
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
|
||||
|
||||
/* Update bitmap */
|
||||
|
||||
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
|
||||
Counter->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
if (neverZero_counters_str !=
|
||||
NULL) { // with llvm 9 we make this the default as the bug in
|
||||
// llvm is then fixed
|
||||
#endif
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
Incr = IRB.CreateAdd(Incr, carry);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
IRB.CreateStore(Incr, MapPtrIdx)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
#ifdef USE_SPLIT
|
||||
// nothing
|
||||
#else
|
||||
|
||||
// Unconditional jump to the destination BB
|
||||
|
||||
IRB.CreateBr(Successors[j]);
|
||||
|
||||
// Replace the original destination to this newly inserted BB
|
||||
|
||||
origBB->replacePhiUsesWith(Successors[j], newBB);
|
||||
BasicBlock *S = Successors[j];
|
||||
S->replacePhiUsesWith(origBB, newBB);
|
||||
TI->setSuccessor(j, newBB);
|
||||
|
||||
#endif
|
||||
// done :)
|
||||
|
||||
inst_blocks++;
|
||||
|
||||
}
|
||||
|
||||
} while (i > 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// save highest location ID to global variable
|
||||
|
||||
if (afl_global_id > MAP_SIZE) {
|
||||
|
||||
uint32_t pow2map = 1, map = afl_global_id;
|
||||
while ((map = map >> 1))
|
||||
pow2map++;
|
||||
FATAL(
|
||||
"We have %u blocks to instrument but the map size is only %u! Edit "
|
||||
"config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
|
||||
"afl-fuzz and llvm_mode.",
|
||||
afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map);
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
|
||||
|
||||
GlobalVariable *AFLFinalLoc = new GlobalVariable(
|
||||
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0,
|
||||
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id);
|
||||
AFLFinalLoc->setAlignment(4);
|
||||
AFLFinalLoc->setInitializer(const_loc);
|
||||
|
||||
}
|
||||
|
||||
/* Say something nice. */
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
if (!inst_blocks)
|
||||
WARNF("No instrumentation targets found.");
|
||||
else {
|
||||
|
||||
char modeline[100];
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
|
||||
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
|
||||
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
|
||||
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
OKF("Instrumented %u locations with no collisions (on average %llu "
|
||||
"collisions would be in afl-gcc/afl-clang-fast) (%s mode).",
|
||||
inst_blocks, calculateCollisions(inst_blocks), modeline);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
char AFLLTOPass::ID = 0;
|
||||
|
||||
static void registerAFLLTOPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLLTOPass());
|
||||
|
||||
}
|
||||
|
||||
static RegisterPass<AFLLTOPass> X("afl-lto", "afl++ LTO instrumentation pass",
|
||||
false, false);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLLTOPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLLTOPass);
|
||||
|
267
llvm_mode/afl-llvm-lto-whitelist.so.cc
Normal file
267
llvm_mode/afl-llvm-lto-whitelist.so.cc
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM-mode instrumentation pass
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
|
||||
from afl-as.c are Michal's fault.
|
||||
|
||||
Copyright 2015, 2016 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
|
||||
|
||||
This library is plugged into LLVM when invoking clang through afl-clang-fast.
|
||||
It tells the compiler to add code roughly equivalent to the bits discussed
|
||||
in ../afl-as.h.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_LLVM_PASS
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class AFLwhitelist : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
AFLwhitelist() : ModulePass(ID) {
|
||||
|
||||
int entries = 0;
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||
if (instWhiteListFilename) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instWhiteListFilename);
|
||||
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
myWhitelist.push_back(line);
|
||||
getline(fileStream, line);
|
||||
entries++;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
PFATAL("afl-llvm-lto-whitelist.so loaded without AFL_LLVM_WHITELIST?!");
|
||||
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "loaded whitelist %s with %d entries\n",
|
||||
instWhiteListFilename, entries);
|
||||
|
||||
}
|
||||
|
||||
// ripped from aflgo
|
||||
static bool isBlacklisted(const Function *F) {
|
||||
|
||||
static const SmallVector<std::string, 5> Blacklist = {
|
||||
|
||||
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
|
||||
|
||||
};
|
||||
|
||||
for (auto const &BlacklistFunc : Blacklist) {
|
||||
|
||||
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
// StringRef getPassName() const override {
|
||||
|
||||
// return "American Fuzzy Lop Instrumentation";
|
||||
// }
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int debug = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
char AFLwhitelist::ID = 0;
|
||||
|
||||
bool AFLwhitelist::runOnModule(Module &M) {
|
||||
|
||||
/* Show a banner */
|
||||
|
||||
char be_quiet = 0;
|
||||
|
||||
if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-lto-whitelist" VERSION cRST
|
||||
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
|
||||
|
||||
} else if (getenv("AFL_QUIET"))
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
if (isBlacklisted(&F)) continue;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
|
||||
if (!myWhitelist.empty()) {
|
||||
|
||||
bool instrumentBlock = 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;
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||
it != myWhitelist.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 (instFilename.str().compare(
|
||||
instFilename.str().length() - it->length(),
|
||||
it->length(), *it) == 0) {
|
||||
|
||||
instrumentBlock = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Either we couldn't figure out our location or the location is
|
||||
* not whitelisted, so we skip instrumentation.
|
||||
* We do this by renaming the function. */
|
||||
if (!instrumentBlock) {
|
||||
|
||||
if (F.getName().compare("main") == 0 ||
|
||||
F.getName().compare("start") == 0 ||
|
||||
F.getName().compare("_start") == 0 ||
|
||||
F.getName().compare("init") == 0 ||
|
||||
F.getName().compare("_init") == 0) {
|
||||
|
||||
// We do not honor be_quiet for this one
|
||||
WARNF("Cannot ignore functions main/init/start");
|
||||
|
||||
} else {
|
||||
|
||||
// StringRef newName = StringRef("ign.") + F.getName();
|
||||
if (debug)
|
||||
SAYF(cMGN "[D] " cRST "renamed %s to ign.%s\n",
|
||||
F.getName().str().c_str(), F.getName().str().c_str());
|
||||
Function *_F(&F);
|
||||
_F->setName("ign." + F.getName());
|
||||
|
||||
}
|
||||
|
||||
} else if (debug)
|
||||
|
||||
SAYF(cMGN "[D] " cRST "function %s is in whitelist\n",
|
||||
F.getName().str().c_str());
|
||||
|
||||
} else {
|
||||
|
||||
PFATAL("Whitelist is empty");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void registerAFLwhitelistpass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLwhitelist());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLwhitelistpass(
|
||||
PassManagerBuilder::EP_ModuleOptimizerEarly, registerAFLwhitelistpass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLwhitelistpass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLwhitelistpass);
|
||||
|
@ -2,12 +2,15 @@
|
||||
american fuzzy lop++ - LLVM-mode instrumentation pass
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
Written by Laszlo Szekeres <lszekeres@google.com>,
|
||||
Adrian Herrera <adrian.herrera@anu.edu.au>,
|
||||
Michal Zalewski
|
||||
|
||||
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
|
||||
from afl-as.c are Michal's fault.
|
||||
|
||||
NGRAM previous location coverage comes from Adrian Herrera.
|
||||
|
||||
Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
@ -27,7 +30,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -47,6 +49,7 @@ typedef long double max_align_t;
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
@ -58,6 +61,8 @@ typedef long double max_align_t;
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
|
||||
#include "llvm-ngram-coverage.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
@ -118,6 +123,9 @@ class AFLCoverage : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
uint32_t ngram_size = 0;
|
||||
uint32_t debug = 0;
|
||||
char * ctx_str = NULL;
|
||||
|
||||
};
|
||||
|
||||
@ -125,12 +133,40 @@ class AFLCoverage : public ModulePass {
|
||||
|
||||
char AFLCoverage::ID = 0;
|
||||
|
||||
/* needed up to 3.9.0 */
|
||||
#if LLVM_VERSION_MAJOR == 3 && \
|
||||
(LLVM_VERSION_MINOR < 9 || \
|
||||
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
|
||||
uint64_t PowerOf2Ceil(unsigned in) {
|
||||
|
||||
uint64_t in64 = in - 1;
|
||||
in64 |= (in64 >> 1);
|
||||
in64 |= (in64 >> 2);
|
||||
in64 |= (in64 >> 4);
|
||||
in64 |= (in64 >> 8);
|
||||
in64 |= (in64 >> 16);
|
||||
in64 |= (in64 >> 32);
|
||||
return in64 + 1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
IntegerType *IntLocTy =
|
||||
IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
|
||||
#endif
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
u32 rand_seed;
|
||||
@ -145,9 +181,12 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
char be_quiet = 0;
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-pass" VERSION cRST " by <lszekeres@google.com>\n");
|
||||
SAYF(cCYA "afl-llvm-pass" VERSION cRST
|
||||
" by <lszekeres@google.com> and <adrian.herrera@anu.edu.au>\n");
|
||||
|
||||
} else
|
||||
|
||||
@ -170,32 +209,171 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
|
||||
#endif
|
||||
|
||||
unsigned PrevLocSize;
|
||||
|
||||
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
|
||||
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
|
||||
ctx_str = getenv("AFL_LLVM_CTX");
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* Decide previous location vector size (must be a power of two) */
|
||||
VectorType *PrevLocTy;
|
||||
|
||||
if (ngram_size_str)
|
||||
if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
|
||||
ngram_size > NGRAM_SIZE_MAX)
|
||||
FATAL(
|
||||
"Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
|
||||
"(%u))",
|
||||
NGRAM_SIZE_MAX);
|
||||
|
||||
if (ngram_size == 1) ngram_size = 0;
|
||||
if (ngram_size)
|
||||
PrevLocSize = ngram_size - 1;
|
||||
else
|
||||
#else
|
||||
if (ngram_size_str)
|
||||
FATAL("Sorry, NGRAM branch coverage is not supported with llvm version %s!",
|
||||
LLVM_VERSION_STRING);
|
||||
#endif
|
||||
PrevLocSize = 1;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
|
||||
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
|
||||
#endif
|
||||
|
||||
if (ctx_str && ngram_size_str)
|
||||
FATAL("you must decide between NGRAM and CTX instrumentation");
|
||||
|
||||
/* Get globals for the SHM region and the previous location. Note that
|
||||
__afl_prev_loc is thread-local. */
|
||||
|
||||
GlobalVariable *AFLMapPtr =
|
||||
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
|
||||
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
|
||||
GlobalVariable *AFLPrevLoc;
|
||||
GlobalVariable *AFLContext;
|
||||
|
||||
if (ctx_str)
|
||||
#ifdef __ANDROID__
|
||||
GlobalVariable *AFLPrevLoc = new GlobalVariable(
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||
#else
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", 0,
|
||||
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
#ifdef __ANDROID__
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||
#else
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc",
|
||||
/* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
|
||||
/* AddressSpace */ 0, /* IsExternallyInitialized */ false);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||
#else
|
||||
GlobalVariable *AFLPrevLoc = new GlobalVariable(
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
|
||||
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* Create the vector shuffle mask for updating the previous block history.
|
||||
Note that the first element of the vector will store cur_loc, so just set
|
||||
it to undef to allow the optimizer to do its thing. */
|
||||
|
||||
SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};
|
||||
|
||||
for (unsigned I = 0; I < PrevLocSize - 1; ++I)
|
||||
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
|
||||
|
||||
for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
|
||||
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
|
||||
|
||||
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
|
||||
#endif
|
||||
|
||||
// other constants we need
|
||||
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
|
||||
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
|
||||
|
||||
LoadInst *PrevCtx; // CTX sensitive coverage
|
||||
|
||||
/* Instrument all the things! */
|
||||
|
||||
int inst_blocks = 0;
|
||||
|
||||
for (auto &F : M) {
|
||||
|
||||
int has_calls = 0;
|
||||
if (debug)
|
||||
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
|
||||
F.size());
|
||||
|
||||
if (isBlacklisted(&F)) continue;
|
||||
|
||||
// AllocaInst *CallingContext = nullptr;
|
||||
|
||||
if (ctx_str && F.size() > 1) { // Context sensitive coverage
|
||||
// load the context ID of the previous function and write to to a local
|
||||
// variable on the stack
|
||||
auto bb = &F.getEntryBlock();
|
||||
BasicBlock::iterator IP = bb->getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
PrevCtx = IRB.CreateLoad(AFLContext);
|
||||
PrevCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
// does the function have calls? and is any of the calls larger than one
|
||||
// basic block?
|
||||
has_calls = 0;
|
||||
for (auto &BB : F) {
|
||||
|
||||
if (has_calls) break;
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee || Callee->size() < 2)
|
||||
continue;
|
||||
else {
|
||||
|
||||
has_calls = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if yes we store a context ID for this function in the global var
|
||||
if (has_calls) {
|
||||
|
||||
ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(MAP_SIZE));
|
||||
StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
|
||||
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
@ -310,6 +488,22 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
// in CTX mode we have to restore the original context for the caller -
|
||||
// she might be calling other functions which need the correct CTX
|
||||
if (ctx_str && has_calls) {
|
||||
|
||||
Instruction *Inst = BB.getTerminator();
|
||||
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
|
||||
|
||||
IRBuilder<> Post_IRB(Inst);
|
||||
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
|
||||
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (AFL_R(100) >= inst_ratio) continue;
|
||||
|
||||
/* Make up cur_loc */
|
||||
@ -356,20 +550,50 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
// fprintf(stderr, " == %d\n", more_than_one);
|
||||
if (more_than_one != 1) continue;
|
||||
#endif
|
||||
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc);
|
||||
|
||||
ConstantInt *CurLoc;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
CurLoc = ConstantInt::get(IntLocTy, cur_loc);
|
||||
else
|
||||
#endif
|
||||
CurLoc = ConstantInt::get(Int32Ty, cur_loc);
|
||||
|
||||
/* Load prev_loc */
|
||||
|
||||
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
|
||||
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
|
||||
Value *PrevLocTrans;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* "For efficiency, we propose to hash the tuple as a key into the
|
||||
hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
|
||||
prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
|
||||
|
||||
if (ngram_size)
|
||||
PrevLocTrans = IRB.CreateXorReduce(PrevLoc);
|
||||
else
|
||||
#endif
|
||||
if (ctx_str)
|
||||
PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLoc, PrevCtx), Int32Ty);
|
||||
else
|
||||
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
|
||||
|
||||
/* Load SHM pointer */
|
||||
|
||||
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
|
||||
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
Value *MapPtrIdx =
|
||||
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, CurLoc));
|
||||
|
||||
Value *MapPtrIdx;
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
MapPtrIdx = IRB.CreateGEP(
|
||||
MapPtr,
|
||||
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, CurLoc), Int32Ty));
|
||||
else
|
||||
#endif
|
||||
MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
|
||||
|
||||
/* Update bitmap */
|
||||
|
||||
@ -449,12 +673,32 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
IRB.CreateStore(Incr, MapPtrIdx)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
/* Set prev_loc to cur_loc >> 1 */
|
||||
/* Update prev_loc history vector (by placing cur_loc at the head of the
|
||||
vector and shuffle the other elements back by one) */
|
||||
|
||||
StoreInst *Store =
|
||||
IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc);
|
||||
StoreInst *Store;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size) {
|
||||
|
||||
Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
|
||||
PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
|
||||
Value *UpdatedPrevLoc = IRB.CreateInsertElement(
|
||||
ShuffledPrevLoc, IRB.CreateLShr(CurLoc, (uint64_t)1), (uint64_t)0);
|
||||
|
||||
Store = IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc);
|
||||
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
|
||||
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
|
||||
AFLPrevLoc);
|
||||
|
||||
}
|
||||
|
||||
inst_blocks++;
|
||||
|
||||
}
|
||||
@ -470,10 +714,11 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
else {
|
||||
|
||||
char modeline[100];
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
|
||||
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
|
||||
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
|
||||
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
OKF("Instrumented %u locations (%s mode, ratio %u%%).", inst_blocks,
|
||||
modeline, inst_ratio);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "cmplog.h"
|
||||
#include "llvm-ngram-coverage.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -41,6 +42,10 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "snapshot-inl.h"
|
||||
#endif
|
||||
|
||||
/* This is a somewhat ugly hack for the experimental 'trace-pc-guard' mode.
|
||||
Basically, we need to make sure that the forkserver is initialized after
|
||||
the LLVM-generated runtime initialization pass, not before. */
|
||||
@ -62,13 +67,18 @@ u8 __afl_area_initial[MAP_SIZE];
|
||||
u8 *__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_prev_loc;
|
||||
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||
u32 __afl_final_loc;
|
||||
u32 __afl_prev_ctx;
|
||||
u32 __afl_cmp_counter;
|
||||
#else
|
||||
__thread u32 __afl_prev_loc;
|
||||
__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||
__thread u32 __afl_final_loc;
|
||||
__thread u32 __afl_prev_ctx;
|
||||
__thread u32 __afl_cmp_counter;
|
||||
#endif
|
||||
|
||||
struct cmp_map *__afl_cmp_map;
|
||||
__thread u32 __afl_cmp_counter;
|
||||
|
||||
/* Running in persistent mode? */
|
||||
|
||||
@ -95,7 +105,7 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
printf("shm_open() failed\n");
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -107,7 +117,7 @@ static void __afl_map_shm(void) {
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
printf("mmap() failed\n");
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -143,7 +153,7 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
printf("shm_open() failed\n");
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -156,7 +166,7 @@ static void __afl_map_shm(void) {
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
printf("mmap() failed\n");
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -174,10 +184,113 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static void __afl_start_snapshots(void) {
|
||||
|
||||
static u8 tmp[4];
|
||||
s32 child_pid;
|
||||
|
||||
u8 child_stopped = 0;
|
||||
|
||||
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
|
||||
while (1) {
|
||||
|
||||
u32 was_killed;
|
||||
int status;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
|
||||
/* If we stopped the child in persistent mode, but there was a race
|
||||
condition and afl-fuzz already issued SIGKILL, write off the old
|
||||
process. */
|
||||
|
||||
if (child_stopped && was_killed) {
|
||||
|
||||
child_stopped = 0;
|
||||
if (waitpid(child_pid, &status, 0) < 0) _exit(1);
|
||||
|
||||
}
|
||||
|
||||
if (!child_stopped) {
|
||||
|
||||
/* Once woken up, create a clone of our process. */
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) _exit(1);
|
||||
|
||||
/* In child process: close fds, resume execution. */
|
||||
|
||||
if (!child_pid) {
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (!afl_snapshot_do()) { raise(SIGSTOP); }
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Special handling for persistent mode: if the child is alive but
|
||||
currently stopped, simply restart it with SIGCONT. */
|
||||
|
||||
kill(child_pid, SIGCONT);
|
||||
child_stopped = 0;
|
||||
|
||||
}
|
||||
|
||||
/* In parent process: write PID to pipe, then wait for child. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1);
|
||||
|
||||
if (waitpid(child_pid, &status, WUNTRACED) < 0) _exit(1);
|
||||
|
||||
/* In persistent mode, the child stops itself with SIGSTOP to indicate
|
||||
a successful run. In this case, we want to wake it up without forking
|
||||
again. */
|
||||
|
||||
if (WIFSTOPPED(status)) child_stopped = 1;
|
||||
|
||||
/* Relay wait status to pipe, then loop back. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Fork server logic. */
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
#ifdef __linux__
|
||||
if (!is_persistent && !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
|
||||
afl_snapshot_init() >= 0) {
|
||||
|
||||
__afl_start_snapshots();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static u8 tmp[4];
|
||||
s32 child_pid;
|
||||
|
||||
@ -260,7 +373,8 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
/* A simplified persistent mode handler, used as explained in README.llvm. */
|
||||
/* A simplified persistent mode handler, used as explained in
|
||||
* llvm_mode/README.md. */
|
||||
|
||||
int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
@ -278,7 +392,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
memset(__afl_area_ptr, 0, MAP_SIZE);
|
||||
__afl_area_ptr[0] = 1;
|
||||
__afl_prev_loc = 0;
|
||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||
|
||||
}
|
||||
|
||||
@ -295,7 +409,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
raise(SIGSTOP);
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
__afl_prev_loc = 0;
|
||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||
|
||||
return 1;
|
||||
|
||||
@ -346,7 +460,7 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
|
||||
|
||||
/* 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 README.llvm.
|
||||
For more info about 'trace-pc-guard', see llvm_mode/README.md.
|
||||
|
||||
The first function (__sanitizer_cov_trace_pc_guard) is called back on every
|
||||
edge (as opposed to every basic block). */
|
||||
@ -399,13 +513,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
|
||||
|
||||
///// CmpLog instrumentation
|
||||
|
||||
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
|
||||
void __cmplog_ins_hook1(uint8_t Arg1, uint8_t Arg2) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
|
||||
void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
|
||||
@ -429,7 +543,7 @@ void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
|
||||
void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
|
||||
@ -450,7 +564,7 @@ void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
|
||||
void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
|
||||
@ -472,19 +586,33 @@ void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp1 = __cmplog_ins_hook1
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp2 = __cmplog_ins_hook2
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp4 = __cmplog_ins_hook4
|
||||
#pragma weak __sanitizer_cov_trace_const_cmp8 = __cmplog_ins_hook8
|
||||
|
||||
#pragma weak __sanitizer_cov_trace_cmp1 = __cmplog_ins_hook1
|
||||
#pragma weak __sanitizer_cov_trace_cmp2 = __cmplog_ins_hook2
|
||||
#pragma weak __sanitizer_cov_trace_cmp4 = __cmplog_ins_hook4
|
||||
#pragma weak __sanitizer_cov_trace_cmp8 = __cmplog_ins_hook8
|
||||
#else
|
||||
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2)
|
||||
__attribute__((alias("__sanitizer_cov_trace_cmp1")));
|
||||
__attribute__((alias("__cmplog_ins_hook1")));
|
||||
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2)
|
||||
__attribute__((alias("__sanitizer_cov_trace_cmp2")));
|
||||
__attribute__((alias("__cmplog_ins_hook2")));
|
||||
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2)
|
||||
__attribute__((alias("__sanitizer_cov_trace_cmp4")));
|
||||
__attribute__((alias("__cmplog_ins_hook4")));
|
||||
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2)
|
||||
__attribute__((alias("__sanitizer_cov_trace_cmp8")));
|
||||
__attribute__((alias("__cmplog_ins_hook8")));
|
||||
|
||||
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook1")));
|
||||
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook2")));
|
||||
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook4")));
|
||||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook8")));
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
|
||||
@ -526,6 +654,8 @@ static int area_is_mapped(void* ptr, size_t len) {
|
||||
|
||||
void __cmplog_rtn_hook(void *ptr1, void *ptr2) {
|
||||
|
||||
if (!__afl_cmp_map) return;
|
||||
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
|
404
llvm_mode/cmplog-instructions-pass.cc
Normal file
404
llvm_mode/cmplog-instructions-pass.cc
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM CmpLog instrumentation
|
||||
--------------------------------------------------
|
||||
|
||||
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016 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 <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sys/time.h>
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class CmpLogInstructions : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CmpLogInstructions() : ModulePass(ID) {
|
||||
|
||||
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||
if (instWhiteListFilename) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instWhiteListFilename);
|
||||
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
myWhitelist.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 4
|
||||
const char *getPassName() const override {
|
||||
|
||||
#else
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "cmplog instructions";
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M);
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
char CmpLogInstructions::ID = 0;
|
||||
|
||||
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
|
||||
std::vector<Instruction *> icomps;
|
||||
LLVMContext & C = M.getContext();
|
||||
|
||||
Type * VoidTy = Type::getVoidTy(C);
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns1 = cast<Function>(c1);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns1 = c1;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns2 = cast<Function>(c2);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns2 = c2;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns4 = cast<Function>(c4);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns4 = c4;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns8 = cast<Function>(c8);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns8 = c8;
|
||||
#endif
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||
for (auto &F : M) {
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
if (!myWhitelist.empty()) {
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
|
||||
bool instrumentBlock = 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 LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
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;
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||
it != myWhitelist.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 (instFilename.str().compare(
|
||||
instFilename.str().length() - it->length(),
|
||||
it->length(), *it) == 0) {
|
||||
|
||||
instrumentBlock = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (!Loc.isUnknown()) {
|
||||
|
||||
DILocation cDILoc(Loc.getAsMDNode(C));
|
||||
|
||||
unsigned int instLine = cDILoc.getLineNumber();
|
||||
StringRef instFilename = cDILoc.getFilename();
|
||||
|
||||
(void)instLine;
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||
it != myWhitelist.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 (instFilename.str().compare(
|
||||
instFilename.str().length() - it->length(),
|
||||
it->length(), *it) == 0) {
|
||||
|
||||
instrumentBlock = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Either we couldn't figure out our location or the location is
|
||||
* not whitelisted, so we skip instrumentation. */
|
||||
if (!instrumentBlock) continue;
|
||||
|
||||
}
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CmpInst *selectcmpInst = nullptr;
|
||||
|
||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
if (selectcmpInst->getPredicate() == CmpInst::ICMP_EQ ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_NE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGT ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGT ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULT ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLT ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) {
|
||||
|
||||
auto op0 = selectcmpInst->getOperand(0);
|
||||
auto op1 = selectcmpInst->getOperand(1);
|
||||
|
||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
||||
|
||||
/* this is probably not needed but we do it anyway */
|
||||
if (!intTyOp0 || !intTyOp1) { continue; }
|
||||
|
||||
icomps.push_back(selectcmpInst);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!icomps.size()) return false;
|
||||
if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp instructions\n";
|
||||
|
||||
for (auto &selectcmpInst : icomps) {
|
||||
|
||||
IRBuilder<> IRB(selectcmpInst->getParent());
|
||||
IRB.SetInsertPoint(selectcmpInst);
|
||||
|
||||
auto op0 = selectcmpInst->getOperand(0);
|
||||
auto op1 = selectcmpInst->getOperand(1);
|
||||
|
||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
||||
|
||||
unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
|
||||
? intTyOp0->getBitWidth()
|
||||
: intTyOp1->getBitWidth();
|
||||
|
||||
std::vector<Value *> args;
|
||||
args.push_back(op0);
|
||||
args.push_back(op1);
|
||||
|
||||
switch (max_size) {
|
||||
|
||||
case 8: IRB.CreateCall(cmplogHookIns1, args, "tmp"); break;
|
||||
case 16: IRB.CreateCall(cmplogHookIns2, args, "tmp"); break;
|
||||
case 32: IRB.CreateCall(cmplogHookIns4, args, "tmp"); break;
|
||||
case 64: IRB.CreateCall(cmplogHookIns8, args, "tmp"); break;
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogInstructions::runOnModule(Module &M) {
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
llvm::errs()
|
||||
<< "Running cmplog-instructions-pass by andreafioraldi@gmail.com\n";
|
||||
else
|
||||
be_quiet = 1;
|
||||
hookInstrs(M);
|
||||
verifyModule(M);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new CmpLogInstructions();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerCmpLogInstructionsPass);
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
|
||||
|
@ -92,6 +92,7 @@ class CmpLogRoutines : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool hookRtns(Module &M);
|
||||
@ -274,7 +275,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
}
|
||||
|
||||
if (!calls.size()) return false;
|
||||
errs() << "Hooking " << calls.size() << " calls with pointers as arguments\n";
|
||||
if (!be_quiet)
|
||||
errs() << "Hooking " << calls.size()
|
||||
<< " calls with pointers as arguments\n";
|
||||
|
||||
for (auto &callInst : calls) {
|
||||
|
||||
@ -302,6 +305,8 @@ bool CmpLogRoutines::runOnModule(Module &M) {
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
llvm::errs()
|
||||
<< "Running cmplog-routines-pass by andreafioraldi@gmail.com\n";
|
||||
else
|
||||
be_quiet = 1;
|
||||
hookRtns(M);
|
||||
verifyModule(M);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
@ -91,6 +92,7 @@ class CompareTransform : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool transformCmps(Module &M, const bool processStrcmp,
|
||||
@ -349,6 +351,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
}
|
||||
|
||||
if (!calls.size()) return false;
|
||||
if (!be_quiet)
|
||||
errs() << "Replacing " << calls.size()
|
||||
<< " calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n";
|
||||
|
||||
@ -408,6 +411,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; }
|
||||
|
||||
if (!be_quiet)
|
||||
errs() << callInst->getCalledFunction()->getName() << ": len " << constLen
|
||||
<< ": " << ConstStr << "\n";
|
||||
|
||||
@ -499,6 +503,8 @@ bool CompareTransform::runOnModule(Module &M) {
|
||||
if (isatty(2) && getenv("AFL_QUIET") == NULL)
|
||||
llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, "
|
||||
"extended by heiko@hexco.de\n";
|
||||
else
|
||||
be_quiet = 1;
|
||||
transformCmps(M, true, true, true, true, true);
|
||||
verifyModule(M);
|
||||
|
||||
|
18
llvm_mode/llvm-ngram-coverage.h
Normal file
18
llvm_mode/llvm-ngram-coverage.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef AFL_NGRAM_CONFIG_H
|
||||
#define AFL_NGRAM_CONFIG_H
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if (MAP_SIZE_POW2 <= 16)
|
||||
typedef u16 PREV_LOC_T;
|
||||
#elif (MAP_SIZE_POW2 <= 32)
|
||||
typedef u32 PREV_LOC_T;
|
||||
#else
|
||||
typedef u64 PREV_LOC_T;
|
||||
#endif
|
||||
|
||||
/* Maximum ngram size */
|
||||
#define NGRAM_SIZE_MAX 16U
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
@ -105,6 +106,7 @@ class SplitComparesTransform : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
int enableFPSplit;
|
||||
@ -1233,8 +1235,8 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
int bitw = 64;
|
||||
|
||||
char *bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
|
||||
if (!bitw_env) bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
|
||||
char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
|
||||
if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
|
||||
if (bitw_env) { bitw = atoi(bitw_env); }
|
||||
|
||||
enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL;
|
||||
@ -1243,7 +1245,8 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
simplifyIntSignedness(M);
|
||||
|
||||
if (isatty(2) && getenv("AFL_QUIET") == NULL) {
|
||||
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";
|
||||
@ -1252,11 +1255,14 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
errs() << "Split-floatingpoint-compare-pass: " << splitFPCompares(M)
|
||||
<< " FP comparisons splitted\n";
|
||||
|
||||
}
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
switch (bitw) {
|
||||
|
||||
case 64:
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
|
||||
@ -1266,6 +1272,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
|
||||
#endif
|
||||
case 32:
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
|
||||
@ -1275,6 +1282,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
|
||||
#endif
|
||||
case 16:
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw
|
||||
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
|
||||
|
||||
@ -1282,7 +1290,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
break;
|
||||
|
||||
default:
|
||||
errs() << "NOT Running split-compare-pass \n";
|
||||
if (!be_quiet) errs() << "NOT Running split-compare-pass \n";
|
||||
return false;
|
||||
break;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
@ -125,6 +126,7 @@ class SplitSwitchesTransform : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
int be_quiet = 0;
|
||||
|
||||
private:
|
||||
bool splitSwitches(Module &M);
|
||||
@ -472,6 +474,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
||||
}
|
||||
|
||||
if (!switches.size()) return false;
|
||||
if (!be_quiet)
|
||||
errs() << "Rewriting " << switches.size() << " switch statements "
|
||||
<< "\n";
|
||||
|
||||
@ -485,14 +488,15 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
||||
BasicBlock *Default = SI->getDefaultDest();
|
||||
unsigned bitw = Val->getType()->getIntegerBitWidth();
|
||||
|
||||
errs() << "switch: " << SI->getNumCases() << " cases " << bitw << " bit\n";
|
||||
if (!be_quiet)
|
||||
errs() << "switch: " << SI->getNumCases() << " cases " << bitw
|
||||
<< " bit\n";
|
||||
|
||||
/* If there is only the default destination or the condition checks 8 bit or
|
||||
* less, don't bother with the code below. */
|
||||
if (!SI->getNumCases() || bitw <= 8) {
|
||||
|
||||
if (isatty(2) && getenv("AFL_QUIET") == NULL)
|
||||
errs() << "skip trivial switch..\n";
|
||||
if (!be_quiet) errs() << "skip trivial switch..\n";
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -559,6 +563,8 @@ bool SplitSwitchesTransform::runOnModule(Module &M) {
|
||||
|
||||
if (isatty(2) && getenv("AFL_QUIET") == NULL)
|
||||
llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n";
|
||||
else
|
||||
be_quiet = 1;
|
||||
splitSwitches(M);
|
||||
verifyModule(M);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user