mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
471 Commits
Author | SHA1 | Date | |
---|---|---|---|
bd0a23de73 | |||
4619a1395b | |||
0c38850f95 | |||
07884e0054 | |||
bdadbb7207 | |||
e389eb9842 | |||
5cf0655071 | |||
f81ef4abf4 | |||
6036cf8437 | |||
1cad645400 | |||
36846836ed | |||
79f1a44a01 | |||
c2127e3ff7 | |||
2ad495ad0a | |||
8e051fd075 | |||
af628b16d1 | |||
c219502f0f | |||
a5da9ce42c | |||
79e02c2a9b | |||
3a461944ec | |||
78d96c4dc8 | |||
ee0ca07f3c | |||
7ae7b0f373 | |||
e2b4bc9310 | |||
6c9777de13 | |||
2f7e57f6aa | |||
5c239451cf | |||
35ca51c5a8 | |||
047f3436e9 | |||
5d181950eb | |||
48a1a29baa | |||
c05d392cd9 | |||
cc7c651dc9 | |||
e6ef2ee338 | |||
a090b2013f | |||
564f491566 | |||
2daeeab844 | |||
4ab90e739f | |||
745bc083d1 | |||
7674dac1a1 | |||
fb2a6b6941 | |||
70fe872940 | |||
a252943236 | |||
8c133b607c | |||
2785c8b197 | |||
a81b5aa921 | |||
8ad78f5b65 | |||
ac9cfd89da | |||
c67c4ce757 | |||
974aab6cf6 | |||
b957218a3a | |||
f629f4e341 | |||
871c3c91ec | |||
100aac4dd3 | |||
d941da33ae | |||
62767a42dc | |||
89cf94f0e6 | |||
17211253b2 | |||
6998489b26 | |||
4290cb5877 | |||
801f2449ec | |||
aaf5fcd98a | |||
5edfb7ba85 | |||
a5cb522f01 | |||
3195119dad | |||
d6fe6b9537 | |||
c0f9fba6d6 | |||
1a713ff420 | |||
89af2ef7a9 | |||
907c5d4276 | |||
5dd35f5281 | |||
857229654e | |||
4c47b242eb | |||
938512a6b9 | |||
7444cfa450 | |||
f091b8d692 | |||
7d97ffb1e8 | |||
80bdbf7be0 | |||
686719cdca | |||
6caec2169c | |||
5212481352 | |||
d999725de2 | |||
145c673a80 | |||
c5017945f7 | |||
5c4c49d9ca | |||
cebde1f9e6 | |||
0298ae82b0 | |||
512f53984c | |||
e3a5c31307 | |||
dd2fd80274 | |||
ffc1fc655f | |||
fe477e96ae | |||
98559ea8b0 | |||
f31d8b8401 | |||
389e348826 | |||
98fd50f78f | |||
95561ec5a7 | |||
fe9da70705 | |||
95c77c8486 | |||
e45333bcf9 | |||
c906c042be | |||
9bd1e19d7f | |||
6ce9230ed6 | |||
1d60c39191 | |||
70651d60bd | |||
385312c658 | |||
87a607c7d0 | |||
1ba5d1008e | |||
129a5adaf1 | |||
d827bc4580 | |||
64e46dcefc | |||
c0b3127b9d | |||
7cfa690d1c | |||
22a3c7f7d0 | |||
16ffbb37f5 | |||
ea05f3f4cd | |||
91f2f057e4 | |||
d44cf1344d | |||
756206e4d7 | |||
2ff6e5023f | |||
223bd70f1f | |||
dd3f4bb41c | |||
f3e783d343 | |||
f4cac37b04 | |||
5b2634f711 | |||
267b085f80 | |||
b6643743d6 | |||
17cbb03ba7 | |||
2cd4624779 | |||
e11665564b | |||
93cebd6c7f | |||
a124540e50 | |||
c465e48e27 | |||
c2c65fd9c1 | |||
0ad56167c5 | |||
aeb7d70483 | |||
209c5ba465 | |||
01327ad301 | |||
96cdc97c98 | |||
a763c61d89 | |||
d920104248 | |||
08076f0500 | |||
e81f30828f | |||
f54c4dbfdb | |||
bf289ce50e | |||
1a8c242d28 | |||
19d8f00963 | |||
bed789cd5a | |||
7e625c3687 | |||
f53a2e4b88 | |||
d8a18a03e3 | |||
1677481726 | |||
6f163bb0c5 | |||
3533df9453 | |||
faa9daf260 | |||
bf1198c4db | |||
ec737f3368 | |||
208254f47c | |||
d0ab2ded00 | |||
58a5372bf0 | |||
ea5d9c42b6 | |||
8bd70a50b1 | |||
6be3896bfa | |||
1f71b85426 | |||
654f389e73 | |||
cd95ee67bc | |||
90fdafa1ad | |||
b9f469e12f | |||
ba7bf99235 | |||
e954c891a0 | |||
80fc6166d0 | |||
4018e7f8e5 | |||
05472a0fc5 | |||
32110a04c0 | |||
812cf4c9e0 | |||
374fa8af47 | |||
fc5f865796 | |||
88155d2c3b | |||
d808a8401e | |||
bca4026f62 | |||
965b854803 | |||
981ffb27a8 | |||
522eacce71 | |||
19d02d7bf6 | |||
cc0210426a | |||
459dd8cb07 | |||
e5116c6d55 | |||
7a861498c2 | |||
893cd47d9c | |||
9d08f0d098 | |||
3b3565269d | |||
2f96f1e920 | |||
1b557d1a70 | |||
b06e3d9f2b | |||
aaec45b652 | |||
af24d87220 | |||
2e3bc3b613 | |||
29c1131fe0 | |||
debd832f36 | |||
8a8ecef6f5 | |||
66c290f804 | |||
40f609c735 | |||
28e1aaa0f1 | |||
6f5746d428 | |||
4488e8e10a | |||
d21ca3e480 | |||
1b1006ddd4 | |||
cb428e55bb | |||
0c616087e0 | |||
ce673ccab3 | |||
d5a170655f | |||
2a9fcd2a87 | |||
a61a30dee0 | |||
d62c83d58f | |||
ad63ba49c1 | |||
1dfea4e91a | |||
47f62eb0ca | |||
9bc8c7518f | |||
2044c7e2b5 | |||
6b721900d5 | |||
f5127c0e2b | |||
f571f074a8 | |||
d046b28f2f | |||
a754694ac4 | |||
36b5336152 | |||
9c393adbb9 | |||
e0663c91b9 | |||
7c381a782e | |||
cd8668ad3a | |||
9a7531942d | |||
107b624224 | |||
822aea3cb4 | |||
52af7caf8a | |||
afc15965c0 | |||
e82cd40440 | |||
08c716da9c | |||
0a3a708f9b | |||
a22c8ffdf2 | |||
4179affe2c | |||
46cef4bc11 | |||
fea0286989 | |||
b0a8bc28d2 | |||
e37e432952 | |||
c4118e869d | |||
258ae1632a | |||
1c19804834 | |||
9ed533a0e3 | |||
baf1ac2e69 | |||
46010a8704 | |||
ac21e4dd73 | |||
f0be89a5b6 | |||
0a12d519f7 | |||
2ef8dc4378 | |||
30148bc1a9 | |||
60764ebdf1 | |||
040bf5a61d | |||
b850951c72 | |||
43edd969d8 | |||
e8c1b43a3d | |||
3903dac1f5 | |||
1ee0946f69 | |||
fc3f06caec | |||
0d472adef0 | |||
ba47bee252 | |||
f7c93d741c | |||
cf5fee7c52 | |||
d20a50a413 | |||
b39b87b2f7 | |||
068bef5eab | |||
5174eb6741 | |||
b9e855b7b5 | |||
f380487bb4 | |||
02079d8ef9 | |||
9dff3495d5 | |||
2cd3010f82 | |||
bb9d275350 | |||
f3ef91e8d6 | |||
ac1117ffae | |||
7ad8f6c717 | |||
9d9e148e5c | |||
1e2da1dfb9 | |||
6dc20fc298 | |||
868ef6c10c | |||
52f1d535bd | |||
0306261fec | |||
17e3e65d96 | |||
e3835b4d68 | |||
e7b572af36 | |||
473b3e5fb0 | |||
86c567fa3a | |||
ed9f94c5b9 | |||
0367f6c723 | |||
292f91a55f | |||
95ee2cdd57 | |||
e91f3b0de6 | |||
ca1eb32552 | |||
a9ebf72a84 | |||
e2d9dc16e3 | |||
0b545aaeb4 | |||
94a15b8ca7 | |||
0c061186cf | |||
bbfaa6092d | |||
a8b0629163 | |||
7b97410060 | |||
8951f90623 | |||
6b375489ed | |||
c8c0983ab8 | |||
c71ce79963 | |||
d36af0d576 | |||
a0e884cf8b | |||
fba8790e32 | |||
8eb00a5dfa | |||
d5049da5e4 | |||
9646960f88 | |||
7ba17d182f | |||
c42875ddea | |||
53c7aaa57b | |||
68acd3d101 | |||
0ddbffd80e | |||
b9ba2805e5 | |||
efd8042431 | |||
dc81f681c9 | |||
4581ad3df9 | |||
3196a5f666 | |||
20a47cb23e | |||
813627cbd3 | |||
1827c65596 | |||
3d1a25ce4e | |||
34732e3c5e | |||
7b8c8cf12f | |||
7eaca9c840 | |||
a06b25538f | |||
9cdf5c4150 | |||
52c221fc48 | |||
4c78bb7080 | |||
59b86b0db0 | |||
1a85fca49f | |||
9d4614ce2f | |||
faefad564b | |||
6b54310452 | |||
caf1fbd632 | |||
a561de6e97 | |||
7acf410ab6 | |||
6c095b3937 | |||
d367b033a2 | |||
7f4b3a460a | |||
251e72f136 | |||
c6e038fe25 | |||
5c22472616 | |||
b7cd6d4035 | |||
1842c8390f | |||
9c15f53a47 | |||
b7af98e945 | |||
5cdbfeef4a | |||
33a7d6f168 | |||
c423aebb1a | |||
58039d181a | |||
880513651d | |||
1857df8d06 | |||
3c88de565a | |||
8bcb17b11f | |||
848db92196 | |||
6ed465bacc | |||
e83a1bc0d1 | |||
33abd70647 | |||
84d3192f01 | |||
d2a1f05a69 | |||
7620f6f396 | |||
214da5c42e | |||
697e3e285b | |||
fac373ec9e | |||
16d2bd3177 | |||
af10a635f5 | |||
935724557f | |||
7e6645d5a2 | |||
271116f870 | |||
84e72b0a51 | |||
b0d69f1b69 | |||
f38595f6b4 | |||
5a99e67e02 | |||
0246fe9200 | |||
5d560c1ece | |||
d687fbdfb4 | |||
e9a306a50e | |||
107c79b84b | |||
80767480f0 | |||
83c1378fc1 | |||
871d42e389 | |||
0922763db1 | |||
d103e39f58 | |||
3f871d1d8f | |||
688f4ffb89 | |||
41dad9ab7d | |||
108e28ff10 | |||
e22db8d609 | |||
f1b4b38152 | |||
8e2b59ffca | |||
7375d8fcb7 | |||
2c4b51b437 | |||
fe0dca9d96 | |||
159707f74c | |||
4af0065f4a | |||
fa933036a7 | |||
0b9ca807f2 | |||
450fd17451 | |||
a4fd4ea0f4 | |||
949f075247 | |||
895d0778b6 | |||
dbdb95bc23 | |||
92bf656cd3 | |||
849b8cd084 | |||
03849d147a | |||
1c79687dfe | |||
1fe3af0418 | |||
7dc433a0c0 | |||
8d10d12ab3 | |||
ceed19f275 | |||
9a5ea5b5c2 | |||
e790667fd2 | |||
8241ded12e | |||
f18afa8ccd | |||
2a994e457a | |||
9759320266 | |||
27b9ba4502 | |||
e8374e3deb | |||
f37cc223d8 | |||
6f0f167b73 | |||
a39228def6 | |||
f7ceafab1c | |||
2a22dc433c | |||
6e27c66058 | |||
7172302be8 | |||
b42f405e60 | |||
816ba61080 | |||
7e27448dac | |||
2a0d066121 | |||
1078409875 | |||
45a68760ee | |||
ed85d5374b | |||
47e04548d4 | |||
6d1f17d78d | |||
c28ecbbb2b | |||
bf3ba489a0 | |||
f9d9ff2cd2 | |||
0b4f6adfee | |||
81e3e991a7 | |||
eddabf6b05 | |||
2e3cf10070 | |||
59c1c6a431 | |||
98ee17bc47 | |||
a6116ed533 | |||
bc9f956c84 | |||
e1a7ed9d6e | |||
7374503f14 | |||
12ebb351dc | |||
73dd6d86ab | |||
2748d5c962 | |||
ea9db86bb8 | |||
4ff9eb0e67 | |||
f0b6576f97 | |||
3ee12009c0 | |||
0011f2047b | |||
79c98731c9 | |||
b6b907705e | |||
fd6bff727a | |||
3282775a15 | |||
d07b0169cb | |||
14c67f15c9 | |||
6e0aeb9833 | |||
db76b06e01 | |||
1fc0918ac0 |
@ -33,13 +33,13 @@ if CLANG_FORMAT_BIN is None:
|
||||
o, _ = p.communicate()
|
||||
o = str(o, "utf-8")
|
||||
o = re.sub(r".*ersion ", "", o)
|
||||
#o = o[len("clang-format version "):].strip()
|
||||
o = o[:o.find(".")]
|
||||
# o = o[len("clang-format version "):].strip()
|
||||
o = o[: o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
print ("clang-format-11 is needed. Aborted.")
|
||||
print("clang-format-11 is needed. Aborted.")
|
||||
exit(1)
|
||||
#if o < 7:
|
||||
# if o < 7:
|
||||
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-7'
|
||||
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
|
||||
@ -52,8 +52,8 @@ if CLANG_FORMAT_BIN is None:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
|
||||
CLANG_FORMAT_BIN = "clang-format-11"
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
line = line.split(":")
|
||||
@ -69,26 +69,47 @@ def custom_format(filename):
|
||||
in_define = False
|
||||
last_line = None
|
||||
out = ""
|
||||
|
||||
|
||||
for line in src.split("\n"):
|
||||
if line.lstrip().startswith("#"):
|
||||
if line[line.find("#")+1:].lstrip().startswith("define"):
|
||||
if line[line.find("#") + 1 :].lstrip().startswith("define"):
|
||||
in_define = True
|
||||
|
||||
if "/*" in line and not line.strip().startswith("/*") and line.endswith("*/") and len(line) < (COLUMN_LIMIT-2):
|
||||
|
||||
if (
|
||||
"/*" in line
|
||||
and not line.strip().startswith("/*")
|
||||
and line.endswith("*/")
|
||||
and len(line) < (COLUMN_LIMIT - 2)
|
||||
):
|
||||
cmt_start = line.rfind("/*")
|
||||
line = line[:cmt_start] + " " * (COLUMN_LIMIT-2 - len(line)) + line[cmt_start:]
|
||||
line = (
|
||||
line[:cmt_start]
|
||||
+ " " * (COLUMN_LIMIT - 2 - len(line))
|
||||
+ line[cmt_start:]
|
||||
)
|
||||
|
||||
define_padding = 0
|
||||
if last_line is not None and in_define and last_line.endswith("\\"):
|
||||
last_line = last_line[:-1]
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n")+1:]))
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
|
||||
|
||||
if last_line is not None and last_line.strip().endswith("{") and line.strip() != "":
|
||||
if (
|
||||
last_line is not None
|
||||
and last_line.strip().endswith("{")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif last_line is not None and last_line.strip().startswith("}") and line.strip() != "":
|
||||
elif (
|
||||
last_line is not None
|
||||
and last_line.strip().startswith("}")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif line.strip().startswith("}") and last_line is not None and last_line.strip() != "":
|
||||
elif (
|
||||
line.strip().startswith("}")
|
||||
and last_line is not None
|
||||
and last_line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
|
||||
if not line.endswith("\\"):
|
||||
@ -97,14 +118,15 @@ def custom_format(filename):
|
||||
out += line + "\n"
|
||||
last_line = line
|
||||
|
||||
return (out)
|
||||
return out
|
||||
|
||||
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print ("Usage: ./format.py [-i] <filename>")
|
||||
print ()
|
||||
print (" The -i option, if specified, let the script to modify in-place")
|
||||
print (" the source files. By default the results are written to stdout.")
|
||||
print("Usage: ./format.py [-i] <filename>")
|
||||
print()
|
||||
print(" The -i option, if specified, let the script to modify in-place")
|
||||
print(" the source files. By default the results are written to stdout.")
|
||||
print()
|
||||
exit(1)
|
||||
|
||||
@ -120,4 +142,3 @@ for filename in args:
|
||||
f.write(code)
|
||||
else:
|
||||
print(code)
|
||||
|
||||
|
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**IMPORTANT**
|
||||
1. You have verified that the issue to be present in the current `dev` branch
|
||||
2. Please supply the command line options and relevant environment variables, e.g. a copy-paste of the contents of `out/default/fuzzer_setup`
|
||||
|
||||
Thank you for making afl++ better!
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screen output/Screenshots**
|
||||
If applicable, add copy-paste of the screen output or screenshot that shows the issue. Please ensure the output is in **English** and not in Chinese, Russian, German, etc.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
27
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
27
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Publish Docker Images
|
||||
on:
|
||||
push:
|
||||
branches: [ stable ]
|
||||
paths:
|
||||
- Dockerfile
|
||||
pull_request:
|
||||
branches: [ stable ]
|
||||
paths:
|
||||
- Dockerfile
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker images to Dockerhub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Publish aflpp to Registry
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: aflplusplus/aflplusplus:latest
|
28
.github/workflows/ci.yml
vendored
Normal file
28
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: '${{ matrix.os }}'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc- ; echo ; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools
|
||||
- name: compiler installed
|
||||
run: gcc -v ; echo ; clang -v
|
||||
- name: install gcc plugin
|
||||
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
|
||||
- name: build afl++
|
||||
run: make distrib ASAN_BUILD=1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config ; export AFL_SKIP_CPUFREQ=1 ; make tests
|
32
.github/workflows/codeql-analysis.yml
vendored
Normal file
32
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -82,3 +82,4 @@ examples/aflpp_driver/libAFLQemuDriver.a
|
||||
libAFLDriver.a
|
||||
libAFLQemuDriver.a
|
||||
test/.afl_performance
|
||||
gmon.out
|
||||
|
59
.travis.yml
59
.travis.yml
@ -1,59 +0,0 @@
|
||||
language: c
|
||||
|
||||
sudo: required
|
||||
|
||||
branches:
|
||||
only:
|
||||
- stable
|
||||
- dev
|
||||
|
||||
matrix:
|
||||
include:
|
||||
#- os: linux # again disabled because fetching packages times out very often :(
|
||||
# dist: focal
|
||||
# env: NAME="focal-amd64" MODERN="yes" GCC="9"
|
||||
- os: linux
|
||||
dist: bionic
|
||||
env: NAME="bionic-amd64" MODERN="yes" GCC="7"
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: NAME="xenial-amd64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0"
|
||||
# - os: linux # disabled: fatal: unable to access 'https://git.qemu.org/git/capstone/': gnutls_handshake() failed: Handshake failed
|
||||
# dist: trusty
|
||||
# env: NAME="trusty-amd64" MODERN="no" GCC="4.8"
|
||||
- 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"
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- arch: arm64
|
||||
|
||||
env:
|
||||
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1
|
||||
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_EXIT_WHEN_DONE=1
|
||||
# TODO: test AFL_BENCH_UNTIL_CRASH once we have a target that crashes
|
||||
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_BENCH_JUST_ONE=1
|
||||
|
||||
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 git libtool libtool-bin automake bison libglib2.0-0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev python3-setuptools ; fi
|
||||
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y git libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils libcmocka-dev python3-setuptools ; fi
|
||||
|
||||
script:
|
||||
- gcc -v
|
||||
- clang -v
|
||||
- sudo -E ./afl-system-config
|
||||
- sudo sysctl -w kernel.shmmax=10000000000
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export LLVM_CONFIG=`pwd`/"$NAME" ; make source-only ASAN_BUILD=1 ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$TRAVIS_CPU_ARCH" = "amd64" ]; then make distrib ASAN_BUILD=1 ; fi
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then 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
|
184
Android.bp
184
Android.bp
@ -1,7 +1,16 @@
|
||||
cc_defaults {
|
||||
name: "afl-defaults",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
|
||||
local_include_dirs: [
|
||||
"include",
|
||||
"instrumentation",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-flto=full",
|
||||
"-funroll-loops",
|
||||
"-Wno-pointer-sign",
|
||||
"-Wno-pointer-arith",
|
||||
@ -10,24 +19,35 @@ cc_defaults {
|
||||
"-Wno-unused-function",
|
||||
"-Wno-format",
|
||||
"-Wno-user-defined-warnings",
|
||||
"-DUSE_TRACE_PC=1",
|
||||
"-DAFL_LLVM_USE_TRACE_PC=1",
|
||||
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
|
||||
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
|
||||
"-D__USE_GNU",
|
||||
"-D__aarch64__",
|
||||
"-DDEBUG_BUILD",
|
||||
"-U_FORTIFY_SOURCE",
|
||||
"-ggdb3",
|
||||
"-g",
|
||||
"-O0",
|
||||
"-fno-omit-frame-pointer",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-fuzz",
|
||||
static_executable: true,
|
||||
host_supported: true,
|
||||
compile_multilib: "64",
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"afl-fuzz.c",
|
||||
"src/afl-fuzz*.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -41,7 +61,11 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"afl-showmap.c",
|
||||
"src/afl-showmap.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -55,7 +79,11 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"afl-tmin.c",
|
||||
"src/afl-tmin.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -69,7 +97,10 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"afl-analyze.c",
|
||||
"src/afl-analyze.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
@ -83,12 +114,13 @@ cc_binary {
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"afl-gotcpu.c",
|
||||
"src/afl-gotcpu.c",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "afl-clang-fast",
|
||||
name: "afl-cc",
|
||||
static_executable: true,
|
||||
|
||||
defaults: [
|
||||
@ -98,44 +130,144 @@ cc_binary_host {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
"-DAFL_CLANG_FLTO=\"-flto=full\"",
|
||||
"-DUSE_BINDIR=1",
|
||||
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
|
||||
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
|
||||
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
|
||||
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
|
||||
"-DLLVM_LTO=1",
|
||||
"-DLLVM_MAJOR=11",
|
||||
"-DLLVM_MINOR=2",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-cc.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "afl-clang-fast++",
|
||||
static_executable: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-cc.c",
|
||||
symlinks: [
|
||||
"afl-clang-fast",
|
||||
"afl-clang-fast++",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "afl-llvm-rt",
|
||||
compile_multilib: "both",
|
||||
compile_multilib: "64",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
recovery_available: true,
|
||||
sdk_version: "9",
|
||||
|
||||
apex_available: [
|
||||
"com.android.adbd",
|
||||
"com.android.appsearch",
|
||||
"com.android.art",
|
||||
"com.android.bluetooth.updatable",
|
||||
"com.android.cellbroadcast",
|
||||
"com.android.conscrypt",
|
||||
"com.android.extservices",
|
||||
"com.android.cronet",
|
||||
"com.android.neuralnetworks",
|
||||
"com.android.media",
|
||||
"com.android.media.swcodec",
|
||||
"com.android.mediaprovider",
|
||||
"com.android.permission",
|
||||
"com.android.runtime",
|
||||
"com.android.resolv",
|
||||
"com.android.tethering",
|
||||
"com.android.wifi",
|
||||
"com.android.sdkext",
|
||||
"com.android.os.statsd",
|
||||
"//any",
|
||||
],
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"instrumentation/afl-llvm-rt.o.c",
|
||||
"instrumentation/afl-compiler-rt.o.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libafl_headers",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
}
|
||||
|
||||
cc_prebuilt_library_static {
|
||||
name: "libfrida-gum",
|
||||
compile_multilib: "64",
|
||||
strip: {
|
||||
none: true,
|
||||
},
|
||||
|
||||
srcs: [
|
||||
"utils/afl_frida/android/libfrida-gum.a",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"utils/afl_frida/android",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libtestinstr",
|
||||
|
||||
srcs: [
|
||||
"utils/afl_frida/libtestinstr.c",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-O0",
|
||||
"-fPIC",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-frida",
|
||||
compile_multilib: "64",
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-Wno-format",
|
||||
"-Wno-pointer-sign",
|
||||
"-fpermissive",
|
||||
"-fPIC",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"afl-llvm-rt",
|
||||
"libfrida-gum",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libdl",
|
||||
"liblog",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"utils/afl_frida/afl-frida.c",
|
||||
],
|
||||
|
||||
local_include_dirs: [
|
||||
"utils/afl_frida",
|
||||
"utils/afl_frida/android",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"custom_mutators",
|
||||
]
|
||||
|
@ -1 +0,0 @@
|
||||
Makefile
|
25
Dockerfile
25
Dockerfile
@ -11,22 +11,25 @@ LABEL "about"="AFLplusplus docker image"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
env NO_ARCH_OPT 1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
automake \
|
||||
ninja-build \
|
||||
bison flex \
|
||||
build-essential \
|
||||
git \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
wget vim jupp nano bash-completion \
|
||||
wget vim jupp nano bash-completion less \
|
||||
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||
libpixman-1-dev \
|
||||
gnuplot-nox \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main" >> /etc/apt/sources.list && \
|
||||
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
|
||||
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
|
||||
RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
|
||||
@ -35,27 +38,27 @@ RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main
|
||||
RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gdb lcov \
|
||||
clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
|
||||
libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \
|
||||
libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \
|
||||
liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \
|
||||
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools \
|
||||
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
|
||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-11
|
||||
ENV LLVM_CONFIG=llvm-config-12
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN git clone https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN cd /afl-cov && make install && cd ..
|
||||
|
||||
COPY . /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
|
||||
RUN export REAL_CXX=g++-10 && export CC=gcc-10 && \
|
||||
export CXX=g++-10 && make clean && \
|
||||
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
|
||||
make distrib && make install && make clean
|
||||
|
||||
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
|
||||
|
84
GNUmakefile
84
GNUmakefile
@ -42,8 +42,8 @@ endif
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
$(info Compiling ASAN version of binaries)
|
||||
override CFLAGS+=$(ASAN_CFLAGS)
|
||||
LDFLAGS+=$(ASAN_LDFLAGS)
|
||||
override CFLAGS += $(ASAN_CFLAGS)
|
||||
LDFLAGS += $(ASAN_LDFLAGS)
|
||||
endif
|
||||
ifdef UBSAN_BUILD
|
||||
$(info Compiling UBSAN version of binaries)
|
||||
@ -57,8 +57,6 @@ ifdef MSAN_BUILD
|
||||
override LDFLAGS += -fsanitize=memory
|
||||
endif
|
||||
|
||||
|
||||
|
||||
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
|
||||
@ -77,30 +75,34 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -
|
||||
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||
endif
|
||||
|
||||
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
# ifndef SOURCE_DATE_EPOCH
|
||||
# HAVE_MARCHNATIVE = 1
|
||||
# CFLAGS_OPT += -march=native
|
||||
# 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"
|
||||
ifndef SOURCE_DATE_EPOCH
|
||||
#CFLAGS_OPT += -march=native
|
||||
SPECIAL_PERFORMANCE += -march=native
|
||||
endif
|
||||
endif
|
||||
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS=-lkstat -lrt
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS = -lkstat -lrt
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries, disabling python though)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYTHON_OK = 0
|
||||
PYFLAGS=
|
||||
PYTHON_INCLUDE=/
|
||||
PYTHON_INCLUDE = /
|
||||
|
||||
CFLAGS_OPT += -static
|
||||
LDFLAGS += -lm -lpthread -lz -lutil
|
||||
@ -117,6 +119,7 @@ ifdef INTROSPECTION
|
||||
CFLAGS_OPT += -DINTROSPECTION=1
|
||||
endif
|
||||
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
@ -131,7 +134,7 @@ ifdef DEBUG
|
||||
$(info Compiling DEBUG version of binaries)
|
||||
CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror
|
||||
else
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
endif
|
||||
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
|
||||
@ -302,7 +305,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
|
||||
|
||||
.PHONY: llvm
|
||||
llvm:
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
@ -361,6 +364,7 @@ help:
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo NO_ARCH_OPT - builds afl++ without machine architecture optimizations
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
@ -409,7 +413,7 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
@ln -sf afl-as as
|
||||
|
||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
||||
$(CC) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
$(CC) $(CFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
@ -423,8 +427,8 @@ src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
@ -504,6 +508,8 @@ code-format:
|
||||
./.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 qemu_mode/libqasan/*.c
|
||||
./.custom-format.py -i qemu_mode/libqasan/*.h
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
@ -512,23 +518,23 @@ code-format:
|
||||
ifndef AFL_NO_X86
|
||||
test_build: afl-cc afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc 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
|
||||
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
|
||||
@echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-gcc does not seem to be behaving correctly!"; \
|
||||
gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option."; echo "See docs/INSTALL.md section 5 how to build a -B enabled gcc." ) || \
|
||||
( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
|
||||
@echo
|
||||
@echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
|
||||
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
|
||||
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
|
||||
# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
# @rm -f test-instr
|
||||
# @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-gcc does not seem to be behaving correctly!"; \
|
||||
# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option."; echo "See docs/INSTALL.md section 5 how to build a -B enabled gcc." ) || \
|
||||
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
|
||||
# @echo
|
||||
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
|
||||
else
|
||||
test_build: afl-cc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
@ -558,6 +564,7 @@ clean:
|
||||
$(MAKE) -C utils/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C qemu_mode/libqasan clean
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
|
||||
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
@ -574,11 +581,11 @@ deepclean: clean
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
$(MAKE) -C utils/aflpp_driver
|
||||
-$(MAKE) -C utils/aflpp_driver
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
@ -586,7 +593,7 @@ distrib: all
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
.PHONY: binary-only
|
||||
binary-only: all
|
||||
binary-only: test_shm test_python ready $(PROGS)
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
@ -597,11 +604,11 @@ binary-only: all
|
||||
|
||||
.PHONY: source-only
|
||||
source-only: all
|
||||
-$(MAKE) -f GNUmakefile.llvm
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
$(MAKE) -C utils/aflpp_driver
|
||||
-$(MAKE) -C utils/aflpp_driver
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@ -633,6 +640,7 @@ install: all $(MANPAGES)
|
||||
@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 libqasan.so ]; then set -e; install -m 755 libqasan.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 utils/socket_fuzzing install; fi
|
||||
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
|
||||
|
@ -138,7 +138,7 @@ afl-common.o: ./src/afl-common.c
|
||||
.PHONY: test_build
|
||||
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) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./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
|
||||
|
@ -43,7 +43,8 @@ endif
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^19' && echo 1 || echo 0 )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^[0-2]\.' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-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_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
@ -58,7 +59,11 @@ ifeq "$(LLVMVER)" ""
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.4 up to 12)
|
||||
$(error llvm_mode only supports llvm from version 3.4 onwards)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_NEW)" "1"
|
||||
$(warning you are using an in-development llvm version - this might break llvm_mode!)
|
||||
endif
|
||||
|
||||
LLVM_TOO_OLD=1
|
||||
@ -208,12 +213,12 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
||||
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
||||
else
|
||||
$(warn ld.lld not found, cannot enable LTO mode)
|
||||
$(warning ld.lld not found, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
else
|
||||
$(warn clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
|
||||
$(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
@ -226,7 +231,7 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
AFL_CLANG_LDPATH=1
|
||||
endif
|
||||
else
|
||||
$(warn -fuse-ld is not working, cannot enable LTO mode)
|
||||
$(warning -fuse-ld is not working, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
@ -357,7 +362,7 @@ instrumentation/afl-common.o: ./src/afl-common.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
./afl-cc: src/afl-cc.c instrumentation/afl-common.o
|
||||
$(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
|
||||
$(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -lm
|
||||
@ln -sf afl-cc ./afl-c++
|
||||
@ln -sf afl-cc ./afl-gcc
|
||||
@ln -sf afl-cc ./afl-g++
|
||||
@ -452,7 +457,7 @@ document:
|
||||
.PHONY: test_build
|
||||
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_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./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
|
||||
|
167
README.md
167
README.md
@ -2,11 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
||||

|
||||
Release Version: [3.10c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Release Version: [3.00c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 3.00a
|
||||
Github Version: 3.11a
|
||||
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
@ -23,26 +21,33 @@
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
If you want to use afl++ for your academic work, check the [papers page](https://aflplus.plus/papers/)
|
||||
on the website.
|
||||
on the website. To cite our work, look at the [Cite](#cite) section.
|
||||
For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast`
|
||||
with `AFL_LLVM_CMPLOG=1`.
|
||||
|
||||
## Major changes in afl++ 3.0
|
||||
## Major changes in afl++ 3.00 + 3.10
|
||||
|
||||
With afl++ 3.0 we introduced changes that break some previous afl and afl++
|
||||
With afl++ 3.10 we introduced the following changes from previous behaviours:
|
||||
* The '+' feature of the '-t' option now means to auto-calculate the timeout
|
||||
with the value given being the maximum timeout. The original meaning of
|
||||
"skipping timeouts instead of abort" is now inherent to the -t option.
|
||||
|
||||
With afl++ 3.00 we introduced changes that break some previous afl and afl++
|
||||
behaviours and defaults:
|
||||
|
||||
* There are no llvm_mode and gcc_plugin subdirectories anymore and there is
|
||||
only one compiler: afl-cc. All previous compilers now symlink to this one
|
||||
compiler. All instrumentation source code is now in the `instrumentation/`
|
||||
folder.
|
||||
only one compiler: afl-cc. All previous compilers now symlink to this one.
|
||||
All instrumentation source code is now in the `instrumentation/` folder.
|
||||
* The gcc_plugin was replaced with a new version submitted by AdaCore that
|
||||
supports more features. thank you!
|
||||
supports more features. Thank you!
|
||||
* qemu_mode got upgraded to QEMU 5.1, but to be able to build this a current
|
||||
ninja build tool version and python3 setuptools are required.
|
||||
qemu_mode also got new options like snapshotting, instrumenting specific
|
||||
shared libraries, etc. Additionally QEMU 5.1 supports more CPU targets so
|
||||
this is really worth it.
|
||||
* When instrumenting targets, afl-cc will not supersede optimizations. This
|
||||
allows to fuzz targets as same as they are built for debug or release.
|
||||
* When instrumenting targets, afl-cc will not supersede optimizations anymore
|
||||
if any were given. This allows to fuzz targets as same as they are built
|
||||
for debug or release.
|
||||
* afl-fuzz:
|
||||
* if neither -M or -S is specified, `-S default` is assumed, so more
|
||||
fuzzers can easily be added later
|
||||
@ -55,6 +60,7 @@ behaviours and defaults:
|
||||
* a caching of testcases can now be performed and can be modified by
|
||||
editing config.h for TESTCASE_CACHE or by specifying the env variable
|
||||
`AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500 (default: 50).
|
||||
* -M mains do not perform trimming
|
||||
* examples/ got renamed to utils/
|
||||
* libtokencap/ libdislocator/ and qdbi_mode/ were moved to utils/
|
||||
* afl-cmin/afl-cmin.bash now search first in PATH and last in AFL_PATH
|
||||
@ -67,9 +73,10 @@ behaviours and defaults:
|
||||
3. [How to fuzz a target](#how-to-fuzz-with-afl)
|
||||
4. [Fuzzing binary-only targets](#fuzzing-binary-only-targets)
|
||||
5. [Good examples and writeups of afl++ usages](#good-examples-and-writeups)
|
||||
6. [Branches](#branches)
|
||||
7. [Want to help?](#help-wanted)
|
||||
8. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
|
||||
6. [CI Fuzzing](#ci-fuzzing)
|
||||
7. [Branches](#branches)
|
||||
8. [Want to help?](#help-wanted)
|
||||
9. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
|
||||
|
||||
## Important features of afl++
|
||||
|
||||
@ -88,7 +95,7 @@ behaviours and defaults:
|
||||
| Ngram prev_loc Coverage | | x(6) | | | |
|
||||
| Context Coverage | | x(6) | | | |
|
||||
| Auto Dictionary | | x(7) | | | |
|
||||
| Snapshot LKM Support | | x | x | (x)(5) | |
|
||||
| Snapshot LKM Support | | x(8) | x(8) | (x)(5) | |
|
||||
|
||||
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
|
||||
@ -97,6 +104,7 @@ behaviours and defaults:
|
||||
5. upcoming, development in the branch
|
||||
6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
|
||||
7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x`
|
||||
8. the snapshot LKM is currently unmaintained due to too many kernel changes coming too fast :-(
|
||||
|
||||
Among others, the following features and patches have been integrated:
|
||||
|
||||
@ -139,9 +147,6 @@ behaviours and defaults:
|
||||
|
||||
## Help wanted
|
||||
|
||||
We were happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)
|
||||
and we will try to participate again in 2021!
|
||||
|
||||
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
|
||||
all the big ideas.
|
||||
@ -206,7 +211,7 @@ These build targets exist:
|
||||
afl++ binaries by passing the STATIC=1 argument to make:
|
||||
|
||||
```shell
|
||||
make all STATIC=1
|
||||
make STATIC=1
|
||||
```
|
||||
|
||||
These build options exist:
|
||||
@ -219,6 +224,7 @@ These build options exist:
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
* NO_ARCH_OPT - builds afl++ without machine architecture optimizations
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
|
||||
|
||||
e.g.: make ASAN_BUILD=1
|
||||
@ -283,9 +289,9 @@ anything below 9 is not recommended.
|
||||
|
|
||||
v
|
||||
+--------------------------------+
|
||||
| if you want to instrument only | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
|
||||
| parts of the target | see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
|
||||
+--------------------------------+ [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
| gcc 5+ is available | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
|
||||
+--------------------------------+ see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
|
||||
[instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
|
|
||||
| if not, or if you do not have a gcc with plugin support
|
||||
|
|
||||
@ -298,17 +304,17 @@ Clickable README links for the chosen compiler:
|
||||
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
|
||||
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
|
||||
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
|
||||
* GCC mode (afl-gcc) has no README as it has no own features
|
||||
* GCC/CLANG mode (afl-gcc/afl-clang) have no README as they have no own features
|
||||
|
||||
You can select the mode for the afl-cc compiler by:
|
||||
1. passing --afl-MODE command line options to the compiler via CFLAGS/CXXFLAGS/CPPFLAGS
|
||||
2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||
1. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||
afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
|
||||
afl-gcc-fast, afl-g++-fast
|
||||
3. using the environment variable AFL_CC_COMPILER with MODE
|
||||
afl-gcc-fast, afl-g++-fast (recommended!)
|
||||
2. using the environment variable AFL_CC_COMPILER with MODE
|
||||
3. passing --afl-MODE command line options to the compiler via CFLAGS/CXXFLAGS/CPPFLAGS
|
||||
|
||||
MODE can be one of: LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN
|
||||
(afl-g*-fast) or GCC (afl-gcc/afl-g++).
|
||||
(afl-g*-fast) or GCC (afl-gcc/afl-g++) or CLANG(afl-clang/afl-clang++).
|
||||
|
||||
Because no afl specific command-line options are accepted (beside the
|
||||
--afl-MODE command), the compile-time tools make fairly broad use of environment
|
||||
@ -338,14 +344,14 @@ The following options are available when you instrument with LTO mode (afl-clang
|
||||
You can read more about this in [instrumentation/README.cmplog.md](instrumentation/README.cmplog.md)
|
||||
|
||||
If you use LTO, LLVM or GCC_PLUGIN mode (afl-clang-fast/afl-clang-lto/afl-gcc-fast)
|
||||
you have the option to selectively only instrument parts of the target that you
|
||||
you have the option to selectively only instrument parts of the target that you
|
||||
are interested in:
|
||||
|
||||
* To instrument only those parts of the target that you are interested in
|
||||
create a file with all the filenames of the source code that should be
|
||||
instrumented.
|
||||
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if either the clang
|
||||
version is below 7 or the CLASSIC instrumentation is used - just put one
|
||||
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if a mode other than
|
||||
DEFAULT/PCGUARD is used or you have llvm > 10.0.0 - just put one
|
||||
filename or function per line (no directory information necessary for
|
||||
filenames9, and either set `export AFL_LLVM_ALLOWLIST=allowlist.txt` **or**
|
||||
`export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per
|
||||
@ -353,10 +359,6 @@ are interested in:
|
||||
unless requested (ALLOWLIST).
|
||||
**NOTE:** During optimization functions might be inlined and then would not match!
|
||||
See [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||
For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the
|
||||
llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html)
|
||||
The llvm sancov format works with the allowlist/denylist feature of afl++
|
||||
however afl++'s format is more flexible.
|
||||
|
||||
There are many more options and modes available however these are most of the
|
||||
time less effective. See:
|
||||
@ -511,10 +513,6 @@ more useful.
|
||||
If you just use one CPU for fuzzing, then you are fuzzing just for fun and not
|
||||
seriously :-)
|
||||
|
||||
Pro tip: load the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM)
|
||||
before the start of afl-fuzz as this improves performance by a x2 speed increase
|
||||
(less if you use a persistent mode harness)!
|
||||
|
||||
#### a) Running afl-fuzz
|
||||
|
||||
Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on
|
||||
@ -597,13 +595,17 @@ For every secondary fuzzer there should be a variation, e.g.:
|
||||
All other secondaries should be used like this:
|
||||
* A third to a half with the MOpt mutator enabled: `-L 0`
|
||||
* run with a different power schedule, available are:
|
||||
`explore (default), fast, coe, lin, quad, exploit, mmopt, rare, seek`
|
||||
`fast (default), explore, coe, lin, quad, exploit, mmopt, rare, seek`
|
||||
which you can set with e.g. `-p seek`
|
||||
|
||||
Also it is recommended to set `export AFL_IMPORT_FIRST=1` to load testcases
|
||||
from other fuzzers in the campaign first.
|
||||
|
||||
You can also use different fuzzers.
|
||||
If you are using afl spinoffs or afl conforming fuzzers, then just use the
|
||||
same -o directory and give it a unique `-S` name.
|
||||
Examples are:
|
||||
* [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/)
|
||||
* [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
|
||||
* [AFLsmart](https://github.com/aflsmart/aflsmart)
|
||||
* [FairFuzz](https://github.com/carolemieux/afl-rb)
|
||||
@ -613,7 +615,7 @@ Examples are:
|
||||
A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL)
|
||||
|
||||
However you can also sync afl++ with honggfuzz, libfuzzer with -entropic, etc.
|
||||
Just show the main fuzzer (-M) with the `-F` option where the queue
|
||||
Just show the main fuzzer (-M) with the `-F` option where the queue/work
|
||||
directory of a different fuzzer is, e.g. `-F /src/target/honggfuzz`.
|
||||
|
||||
#### c) The status of the fuzz campaign
|
||||
@ -678,7 +680,6 @@ switch or honggfuzz.
|
||||
|
||||
* Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase)
|
||||
* If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md)
|
||||
* Linux: Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase)
|
||||
* Linux: Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure)
|
||||
* Linux: Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem
|
||||
* Use your cores! [3.b) Using multiple cores/threads](#b-using-multiple-coresthreads)
|
||||
@ -695,8 +696,11 @@ If you want to know more, the rest of this README and the tons of texts in
|
||||
Note that there are also a lot of tools out there that help fuzzing with afl++
|
||||
(some might be deprecated or unsupported):
|
||||
|
||||
Speeding up fuzzing:
|
||||
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the function you want to fuzz requires loading a file, this allows using the shared memory testcase feature :-) - recommended.
|
||||
|
||||
Minimization of test cases:
|
||||
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin that tries to speed up the process of the minimization of test case by using many CPU cores.
|
||||
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin that tries to speed up the process of minimization of a single test case by using many CPU cores.
|
||||
* [afl-ddmin-mod](https://github.com/MarkusTeufelberger/afl-ddmin-mod) - a variation of afl-tmin based on the ddmin algorithm.
|
||||
* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast utility for minimizing test cases by Tavis Ormandy based on parallelization.
|
||||
|
||||
@ -724,11 +728,57 @@ Crash processing
|
||||
* [AFLize](https://github.com/d33tah/aflize) - a tool that automatically generates builds of debian packages suitable for AFL.
|
||||
* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for working with input data.
|
||||
|
||||
## CI Fuzzing
|
||||
|
||||
Some notes on CI Fuzzing - this fuzzing is different to normal fuzzing
|
||||
campaigns as these are much shorter runnings.
|
||||
|
||||
1. Always:
|
||||
* LTO has a much longer compile time which is diametrical to short fuzzing -
|
||||
hence use afl-clang-fast instead.
|
||||
* If you compile with CMPLOG then you can save fuzzing time and reuse that
|
||||
compiled target for both the -c option and the main fuzz target.
|
||||
This will impact the speed by ~15% though.
|
||||
* `AFL_FAST_CAL` - Enable fast calibration, this halfs the time the saturated
|
||||
corpus needs to be loaded.
|
||||
* `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new found paths, not the
|
||||
initial corpus as this very likely has been done for them already.
|
||||
* Keep the generated corpus, use afl-cmin and reuse it everytime!
|
||||
|
||||
2. Additionally randomize the afl++ compilation options, e.g.
|
||||
* 40% for `AFL_LLVM_CMPLOG`
|
||||
* 10% for `AFL_LLVM_LAF_ALL`
|
||||
|
||||
3. Also randomize the afl-fuzz runtime options, e.g.
|
||||
* 60% for `AFL_DISABLE_TRIM`
|
||||
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
|
||||
* 50% use MOpt (`-L 0`)
|
||||
* 40% for `AFL_EXPAND_HAVOC_NOW`
|
||||
* 30% for old queue processing (`-Z`)
|
||||
* for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3`
|
||||
|
||||
4. Do *not* run any `-M` modes, just running `-S` modes is better for CI fuzzing.
|
||||
`-M` enables deterministic fuzzing, old queue handling etc. which is good for
|
||||
a fuzzing campaign but not good for short CI runs.
|
||||
|
||||
How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/4bb61df7905c6005000f5766e966e6fe30ab4559/infra/base-images/base-builder/compile_afl#L69).
|
||||
|
||||
## Fuzzing binary-only targets
|
||||
|
||||
When source code is *NOT* available, afl++ offers various support for fast,
|
||||
on-the-fly instrumentation of black-box binaries.
|
||||
|
||||
If you do not have to use Unicorn the following setup is recommended:
|
||||
* run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`)
|
||||
* run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`)
|
||||
* run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`)
|
||||
|
||||
Then run as many instances as you have cores left with either -Q mode or - better -
|
||||
use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc.
|
||||
|
||||
For Qemu mode, check out the persistent mode and snapshot features, they give
|
||||
a huge speed improvement!
|
||||
|
||||
### QEMU
|
||||
|
||||
For linux programs and its libraries this is accomplished with a version of
|
||||
@ -739,7 +789,8 @@ feature by doing:
|
||||
cd qemu_mode
|
||||
./build_qemu_support.sh
|
||||
```
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) -
|
||||
check out the snapshot feature! :-)
|
||||
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, and is
|
||||
less conducive to parallelization.
|
||||
@ -747,11 +798,13 @@ less conducive to parallelization.
|
||||
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
|
||||
your binary, then you can use afl-fuzz normally and it will have twice
|
||||
the speed compared to qemu_mode (but slower than persistent mode).
|
||||
Note that several other binary rewriters exist, all with their advantages and
|
||||
caveats.
|
||||
|
||||
### Unicorn
|
||||
|
||||
For non-Linux binaries you can use afl++'s unicorn mode which can emulate
|
||||
anything you want - for the price of speed and the user writing scripts.
|
||||
anything you want - for the price of speed and user written scripts.
|
||||
See [unicorn_mode](unicorn_mode/README.md).
|
||||
|
||||
It can be easily built by:
|
||||
@ -763,16 +816,16 @@ cd unicorn_mode
|
||||
### Shared libraries
|
||||
|
||||
If the goal is to fuzz a dynamic library then there are two options available.
|
||||
For both you need to write a small hardness that loads and calls the library.
|
||||
For both you need to write a small harness that loads and calls the library.
|
||||
Faster is the frida solution: [utils/afl_frida/README.md](utils/afl_frida/README.md)
|
||||
|
||||
Another, less precise and slower option is using ptrace with debugger interrupt
|
||||
instrumentation: [utils/afl_untracer/README.md](utils/afl_untracer/README.md)
|
||||
instrumentation: [utils/afl_untracer/README.md](utils/afl_untracer/README.md).
|
||||
|
||||
### More
|
||||
|
||||
A more comprehensive description of these and other options can be found in
|
||||
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
|
||||
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md).
|
||||
|
||||
## Challenges of guided fuzzing
|
||||
|
||||
@ -1114,7 +1167,7 @@ without feedback, bug reports, or patches from:
|
||||
Khaled Yakdan Kuang-che Wu
|
||||
Josephine Calliotte Konrad Welc
|
||||
Thomas Rooijakkers David Carlier
|
||||
Ruben ten Hove
|
||||
Ruben ten Hove Joey Jiao
|
||||
```
|
||||
|
||||
Thank you!
|
||||
@ -1122,8 +1175,18 @@ Thank you!
|
||||
|
||||
## Cite
|
||||
|
||||
If you use AFLpluplus to compare to your work, please use either `afl-clang-lto`
|
||||
or `afl-clang-fast` with `AFL_LLVM_CMPLOG=1` for building targets and
|
||||
`afl-fuzz` with the command line option `-l 2` for fuzzing.
|
||||
The most effective setup is the `aflplusplus` default configuration on Google's [fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
|
||||
|
||||
If you use AFLplusplus in scientific work, consider citing [our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi) presented at WOOT'20:
|
||||
```
|
||||
|
||||
+ Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.
|
||||
|
||||
Bibtex:
|
||||
|
||||
```bibtex
|
||||
@inproceedings {AFLplusplus-Woot20,
|
||||
author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
|
||||
title = {{AFL++}: Combining Incremental Steps of Fuzzing Research},
|
||||
|
5
TODO.md
5
TODO.md
@ -6,16 +6,13 @@
|
||||
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||
- afl-plot to support multiple plot_data
|
||||
- afl_custom_fuzz_splice_optin()
|
||||
- afl_custom_splice()
|
||||
- intel-pt tracer
|
||||
|
||||
## Further down the road
|
||||
|
||||
afl-fuzz:
|
||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||
- add __sanitizer_cov_trace_cmp* support via shmem
|
||||
|
||||
llvm_mode:
|
||||
- add __sanitizer_cov_trace_cmp* support
|
||||
|
||||
qemu_mode:
|
||||
- non colliding instrumentation
|
||||
|
63
afl-cmin
63
afl-cmin
@ -120,6 +120,7 @@ function usage() {
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
|
||||
"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
||||
exit 1
|
||||
@ -182,14 +183,12 @@ BEGIN {
|
||||
if (_go_c == "Q") {
|
||||
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -Q"
|
||||
if ( !mem_limit_given ) mem_limit = "250"
|
||||
qemu_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "U") {
|
||||
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -U"
|
||||
if ( !mem_limit_given ) mem_limit = "250"
|
||||
unicorn_mode = 1
|
||||
continue
|
||||
} else
|
||||
@ -199,7 +198,7 @@ BEGIN {
|
||||
usage()
|
||||
} # while options
|
||||
|
||||
if (!mem_limit) mem_limit = 200
|
||||
if (!mem_limit) mem_limit = "none"
|
||||
if (!timeout) timeout = "none"
|
||||
|
||||
# get program args
|
||||
@ -344,7 +343,7 @@ BEGIN {
|
||||
stat_format = "-f '%z %N'" # *BSD, MacOS
|
||||
}
|
||||
cmdline = "cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} \\; | sort -k1n -k2r"
|
||||
cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format") | sort -k1n -k2r"
|
||||
cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
|
||||
while (cmdline | getline) {
|
||||
sub(/^[0-9]+ (\.\/)?/,"",$0)
|
||||
infilesSmallToBig[i++] = $0
|
||||
@ -356,7 +355,7 @@ BEGIN {
|
||||
# Make sure that we're not dealing with a directory.
|
||||
|
||||
if (0 == system("test -d "in_dir"/"first_file)) {
|
||||
print "[-] Error: The input directory contains subdirectories - please fix." > "/dev/stderr"
|
||||
print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -366,33 +365,35 @@ BEGIN {
|
||||
cp_tool = "cp"
|
||||
}
|
||||
|
||||
# Make sure that we can actually get anything out of afl-showmap before we
|
||||
# waste too much time.
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) {
|
||||
# Make sure that we can actually get anything out of afl-showmap before we
|
||||
# waste too much time.
|
||||
|
||||
print "[*] Testing the target binary..."
|
||||
print "[*] Testing the target binary..."
|
||||
|
||||
if (!stdin_file) {
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
|
||||
} else {
|
||||
system("cp "in_dir"/"first_file" "stdin_file)
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
first_count = 0
|
||||
|
||||
runtest = trace_dir"/.run_test"
|
||||
while ((getline < runtest) > 0) {
|
||||
++first_count
|
||||
}
|
||||
|
||||
if (first_count) {
|
||||
print "[+] OK, "first_count" tuples recorded."
|
||||
} else {
|
||||
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
if (!stdin_file) {
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
|
||||
} else {
|
||||
system("cp "in_dir"/"first_file" "stdin_file)
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
first_count = 0
|
||||
|
||||
runtest = trace_dir"/.run_test"
|
||||
while ((getline < runtest) > 0) {
|
||||
++first_count
|
||||
}
|
||||
|
||||
if (first_count) {
|
||||
print "[+] OK, "first_count" tuples recorded."
|
||||
} else {
|
||||
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Let's roll!
|
||||
@ -410,8 +411,8 @@ BEGIN {
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""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)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""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_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval && !AFL_CMIN_CRASHES_ONLY) {
|
||||
|
@ -45,7 +45,7 @@ echo
|
||||
|
||||
# Process command-line options...
|
||||
|
||||
MEM_LIMIT=200
|
||||
MEM_LIMIT=none
|
||||
TIMEOUT=none
|
||||
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
@ -85,12 +85,10 @@ while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
;;
|
||||
"Q")
|
||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||
QEMU_MODE=1
|
||||
;;
|
||||
"U")
|
||||
EXTRA_PAR="$EXTRA_PAR -U"
|
||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||
UNICORN_MODE=1
|
||||
;;
|
||||
"?")
|
||||
|
11
afl-plot
11
afl-plot
@ -99,7 +99,7 @@ if [ ! -d "$outputdir" ]; then
|
||||
|
||||
fi
|
||||
|
||||
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png"
|
||||
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
|
||||
mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
|
||||
|
||||
echo "[*] Generating plots..."
|
||||
@ -152,6 +152,12 @@ set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
|
||||
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
|
||||
|
||||
set terminal png truecolor enhanced size 1000,300 butt
|
||||
set output '$outputdir/edges.png'
|
||||
|
||||
set ytics auto
|
||||
plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
|
||||
|
||||
_EOF_
|
||||
|
||||
) | gnuplot
|
||||
@ -172,6 +178,7 @@ cat >"$outputdir/index.html" <<_EOF_
|
||||
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="edges.png" width=1000 height=300>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
@ -183,7 +190,7 @@ _EOF_
|
||||
# sensitive, this seems like a reasonable trade-off.
|
||||
|
||||
chmod 755 "$outputdir"
|
||||
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/index.html"
|
||||
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png" "$outputdir/index.html"
|
||||
|
||||
echo "[+] All done - enjoy your charts!"
|
||||
|
||||
|
@ -34,6 +34,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
|
||||
test -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
||||
test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
|
||||
test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
|
||||
test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
||||
@ -48,6 +49,12 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then
|
||||
sysctl kern.elf64.aslr.enable=0
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||
echo ' sysctl hw.ibrs_disable=1'
|
||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
||||
@ -58,6 +65,17 @@ if [ "$PLATFORM" = "OpenBSD" ] ; then
|
||||
echo 'System security features cannot be disabled on OpenBSD.'
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "DragonFly" ] ; then
|
||||
#/sbin/sysctl kern.corefile=/dev/null
|
||||
#echo Settings applied.
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "NetBSD" ] ; then
|
||||
{
|
||||
#echo It is recommended to enable unprivileged users to set cpu affinity
|
||||
@ -79,4 +97,14 @@ if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
fi
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Haiku" ] ; then
|
||||
SETTINGS=~/config/settings/system/debug_server/settings
|
||||
[ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \
|
||||
echo We change the debug_server default_action from user to silently kill; \
|
||||
[ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \
|
||||
echo Settings applied.; \
|
||||
}
|
||||
DONE=1
|
||||
fi
|
||||
test -z "$DONE" && echo Error: Unknown platform: $PLATFORM
|
||||
exit 0
|
||||
|
@ -28,9 +28,9 @@ if not os.getenv("AFL_INST_LIBS"):
|
||||
os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
|
||||
|
||||
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
|
||||
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so")
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64"
|
||||
else:
|
||||
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so")
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32"
|
||||
|
||||
if os.getenv("WINECOV_QEMU_PATH"):
|
||||
qemu_path = os.getenv("WINECOV_QEMU_PATH")
|
||||
|
115
custom_mutators/Android.bp
Normal file
115
custom_mutators/Android.bp
Normal file
@ -0,0 +1,115 @@
|
||||
cc_library_shared {
|
||||
name: "libfuzzer-mutator",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
"-fpermissive",
|
||||
"-std=c++11",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"libfuzzer/FuzzerCrossOver.cpp",
|
||||
"libfuzzer/FuzzerDataFlowTrace.cpp",
|
||||
"libfuzzer/FuzzerDriver.cpp",
|
||||
"libfuzzer/FuzzerExtFunctionsDlsym.cpp",
|
||||
"libfuzzer/FuzzerExtFunctionsWeak.cpp",
|
||||
"libfuzzer/FuzzerExtFunctionsWindows.cpp",
|
||||
"libfuzzer/FuzzerExtraCounters.cpp",
|
||||
"libfuzzer/FuzzerFork.cpp",
|
||||
"libfuzzer/FuzzerIO.cpp",
|
||||
"libfuzzer/FuzzerIOPosix.cpp",
|
||||
"libfuzzer/FuzzerIOWindows.cpp",
|
||||
"libfuzzer/FuzzerLoop.cpp",
|
||||
"libfuzzer/FuzzerMerge.cpp",
|
||||
"libfuzzer/FuzzerMutate.cpp",
|
||||
"libfuzzer/FuzzerSHA1.cpp",
|
||||
"libfuzzer/FuzzerTracePC.cpp",
|
||||
"libfuzzer/FuzzerUtil.cpp",
|
||||
"libfuzzer/FuzzerUtilDarwin.cpp",
|
||||
"libfuzzer/FuzzerUtilFuchsia.cpp",
|
||||
"libfuzzer/FuzzerUtilLinux.cpp",
|
||||
"libfuzzer/FuzzerUtilPosix.cpp",
|
||||
"libfuzzer/FuzzerUtilWindows.cpp",
|
||||
"libfuzzer/libfuzzer.cpp",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libafl_headers",
|
||||
],
|
||||
}
|
||||
|
||||
/*cc_library_shared {
|
||||
name: "honggfuzz-mutator",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
"-Wl,-Bsymbolic",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"honggfuzz/honggfuzz.c",
|
||||
"honggfuzz/mangle.c",
|
||||
// "../src/afl-perfomance.c",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libafl_headers",
|
||||
],
|
||||
}*/
|
||||
|
||||
cc_library_shared {
|
||||
name: "radamsa-mutator",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"radamsa/libradamsa.c",
|
||||
"radamsa/radamsa-mutator.c",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libafl_headers",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "symcc-mutator",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"symcc/symcc.c",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libafl_headers",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"libprotobuf-mutator-example",
|
||||
]
|
@ -39,7 +39,7 @@
|
||||
#include "libhfcommon/util.h"
|
||||
|
||||
#define PROG_NAME "honggfuzz"
|
||||
#define PROG_VERSION "2.3"
|
||||
#define PROG_VERSION "2.4"
|
||||
|
||||
/* Name of the template which will be replaced with the proper name of the file */
|
||||
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||
@ -208,6 +208,7 @@ typedef struct {
|
||||
const char* crashDir;
|
||||
const char* covDirNew;
|
||||
bool saveUnique;
|
||||
bool saveSmaller;
|
||||
size_t dynfileqMaxSz;
|
||||
size_t dynfileqCnt;
|
||||
dynfile_t* dynfileqCurrent;
|
||||
@ -279,9 +280,9 @@ typedef struct {
|
||||
cmpfeedback_t* cmpFeedbackMap;
|
||||
int cmpFeedbackFd;
|
||||
bool cmpFeedback;
|
||||
const char* blacklistFile;
|
||||
uint64_t* blacklist;
|
||||
size_t blacklistCnt;
|
||||
const char* blocklistFile;
|
||||
uint64_t* blocklist;
|
||||
size_t blocklistCnt;
|
||||
bool skipFeedbackOnTimeout;
|
||||
uint64_t maxCov[4];
|
||||
dynFileMethod_t dynFileMethod;
|
||||
|
@ -77,11 +77,11 @@ static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
|
||||
}
|
||||
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||
|
||||
static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
|
||||
*buf = queue_input;
|
||||
static inline const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) {
|
||||
*len = queue_input_size;
|
||||
run->dynfile->data = queue_input;
|
||||
run->dynfile->size = queue_input_size;
|
||||
return queue_input_size;
|
||||
return queue_input;
|
||||
}
|
||||
static inline void input_setSize(run_t* run, size_t sz) {
|
||||
run->dynfile->size = sz;
|
||||
|
@ -1 +0,0 @@
|
||||
.
|
3
custom_mutators/honggfuzz/libhfcommon/common.h
Normal file
3
custom_mutators/honggfuzz/libhfcommon/common.h
Normal file
@ -0,0 +1,3 @@
|
||||
#ifndef LOG_E
|
||||
#define LOG_E LOG_F
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -246,7 +246,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
|
||||
|
||||
}
|
||||
|
||||
if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
|
||||
if (FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
|
||||
return false;
|
||||
|
||||
// Read traces.
|
||||
@ -259,8 +259,8 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
|
||||
if (!CorporaHashes.count(Name)) continue; // not in the corpus.
|
||||
NumTraceFiles++;
|
||||
// Printf("=== %s\n", Name.c_str());
|
||||
std::ifstream IF(SF.File);
|
||||
while (std::getline(IF, L, '\n')) {
|
||||
std::ifstream IF2(SF.File);
|
||||
while (std::getline(IF2, L, '\n')) {
|
||||
|
||||
size_t FunctionNum = 0;
|
||||
std::string DFTString;
|
||||
@ -314,8 +314,8 @@ int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
|
||||
// we then request tags in [0,Size/2) and [Size/2, Size), and so on.
|
||||
// Function number => DFT.
|
||||
auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
|
||||
std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
|
||||
std::unordered_set<std::string> Cov;
|
||||
// std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
|
||||
// std::unordered_set<std::string> Cov;
|
||||
Command Cmd;
|
||||
Cmd.addArgument(DFTBinary);
|
||||
Cmd.addArgument(F.File);
|
||||
|
@ -46,7 +46,7 @@ template<typename T>
|
||||
fuzzer_allocator() = default;
|
||||
|
||||
template<class U>
|
||||
fuzzer_allocator(const fuzzer_allocator<U>&) {}
|
||||
explicit fuzzer_allocator(const fuzzer_allocator<U>&) {}
|
||||
|
||||
template<class Other>
|
||||
struct rebind { typedef fuzzer_allocator<Other> other; };
|
||||
|
@ -49,7 +49,7 @@ typedef FixedWord<64> Word;
|
||||
class DictionaryEntry {
|
||||
public:
|
||||
DictionaryEntry() {}
|
||||
DictionaryEntry(Word W) : W(W) {}
|
||||
explicit DictionaryEntry(Word W) : W(W) {}
|
||||
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
|
||||
const Word &GetW() const { return W; }
|
||||
|
||||
@ -92,7 +92,7 @@ class Dictionary {
|
||||
assert(Idx < Size);
|
||||
return DE[Idx];
|
||||
}
|
||||
void push_back(DictionaryEntry DE) {
|
||||
void push_back(const DictionaryEntry &DE) {
|
||||
if (Size < kMaxDictSize)
|
||||
this->DE[Size++] = DE;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
namespace fuzzer {
|
||||
class Random : public std::minstd_rand {
|
||||
public:
|
||||
Random(unsigned int seed) : std::minstd_rand(seed) {}
|
||||
explicit Random(unsigned int seed) : std::minstd_rand(seed) {}
|
||||
result_type operator()() { return this->std::minstd_rand::operator()(); }
|
||||
size_t Rand() { return this->operator()(); }
|
||||
size_t RandBool() { return Rand() % 2; }
|
||||
|
@ -145,10 +145,10 @@ private:
|
||||
};
|
||||
Region *Regions;
|
||||
size_t NumRegions;
|
||||
uint8_t *Start() { return Regions[0].Start; }
|
||||
uint8_t *Stop() { return Regions[NumRegions - 1].Stop; }
|
||||
size_t Size() { return Stop() - Start(); }
|
||||
size_t Idx(uint8_t *P) {
|
||||
uint8_t *Start() const { return Regions[0].Start; }
|
||||
uint8_t *Stop() const { return Regions[NumRegions - 1].Stop; }
|
||||
size_t Size() const { return Stop() - Start(); }
|
||||
size_t Idx(uint8_t *P) const {
|
||||
assert(P >= Start() && P < Stop());
|
||||
return P - Start();
|
||||
}
|
||||
|
32
custom_mutators/libprotobuf-mutator-example/Android.bp
Normal file
32
custom_mutators/libprotobuf-mutator-example/Android.bp
Normal file
@ -0,0 +1,32 @@
|
||||
cc_library_shared {
|
||||
name: "libprotobuf-mutator-example-afl",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-fPIC",
|
||||
"-Wall",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"lpm_aflpp_custom_mutator_input.cc",
|
||||
"test.proto",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libprotobuf-cpp-full",
|
||||
"libprotobuf-mutator",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "libprotobuf-mutator-vuln",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
srcs: [
|
||||
"vuln.c",
|
||||
],
|
||||
}
|
1
custom_mutators/libprotobuf-mutator-example/README.md
Normal file
1
custom_mutators/libprotobuf-mutator-example/README.md
Normal file
@ -0,0 +1 @@
|
||||
Ported from [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input)
|
@ -0,0 +1,118 @@
|
||||
#include "lpm_aflpp_custom_mutator_input.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
std::string ProtoToData(const TEST &test_proto) {
|
||||
std::stringstream all;
|
||||
const auto &aa = test_proto.a();
|
||||
const auto &bb = test_proto.b();
|
||||
all.write((const char*)&aa, sizeof(aa));
|
||||
if(bb.size() != 0) {
|
||||
all.write(bb.c_str(), bb.size());
|
||||
}
|
||||
|
||||
std::string res = all.str();
|
||||
if (bb.size() != 0 && res.size() != 0) {
|
||||
// set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf
|
||||
if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) {
|
||||
std::ofstream of(dump_path);
|
||||
of.write(res.data(), res.size());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
extern "C" MyMutator *afl_custom_init(void *afl, unsigned int seed) {
|
||||
MyMutator *mutator = new MyMutator();
|
||||
|
||||
mutator->RegisterPostProcessor(
|
||||
TEST::descriptor(),
|
||||
[](google::protobuf::Message* message, unsigned int seed) {
|
||||
// libprotobuf-mutator's built-in mutator is kind of....crappy :P
|
||||
// Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q
|
||||
// We register a post processor to apply our dumb fuzz
|
||||
|
||||
TEST *t = static_cast<TEST *>(message);
|
||||
t->set_a(rand());
|
||||
});
|
||||
|
||||
srand(seed);
|
||||
return mutator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
extern "C" size_t afl_custom_fuzz(MyMutator *mutator, // return value from afl_custom_init
|
||||
uint8_t *buf, size_t buf_size, // input data to be mutated
|
||||
uint8_t **out_buf, // output buffer
|
||||
uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL
|
||||
size_t max_size) {
|
||||
// This function can be named either "afl_custom_fuzz" or "afl_custom_mutator"
|
||||
// A simple test shows that "buf" will be the content of the current test case
|
||||
// "add_buf" will be the next test case ( from AFL++'s input queue )
|
||||
|
||||
TEST input;
|
||||
// parse input data to TEST
|
||||
// Notice that input data should be a serialized protobuf data
|
||||
// Check ./in/ii and test_protobuf_serializer for more detail
|
||||
bool parse_ok = input.ParseFromArray(buf, buf_size);
|
||||
if(!parse_ok) {
|
||||
// Invalid serialize protobuf data. Don't mutate.
|
||||
// Return a dummy buffer. Also mutated_size = 0
|
||||
static uint8_t *dummy = new uint8_t[10]; // dummy buffer with no data
|
||||
*out_buf = dummy;
|
||||
return 0;
|
||||
}
|
||||
// mutate the protobuf
|
||||
mutator->Mutate(&input, max_size);
|
||||
|
||||
// Convert protobuf to raw data
|
||||
const TEST *p = &input;
|
||||
std::string s = ProtoToData(*p);
|
||||
// Copy to a new buffer ( mutated_out )
|
||||
size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size
|
||||
uint8_t *mutated_out = new uint8_t[mutated_size+1];
|
||||
memcpy(mutated_out, s.c_str(), mutated_size); // copy the mutated data
|
||||
// Assign the mutated data and return mutated_size
|
||||
*out_buf = mutated_out;
|
||||
return mutated_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
extern "C" void afl_custom_deinit(void *data) {
|
||||
// Honestly I don't know what to do with this...
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
#include <src/mutator.h>
|
||||
#include "test.pb.h"
|
||||
|
||||
class MyMutator : public protobuf_mutator::Mutator {
|
||||
};
|
7
custom_mutators/libprotobuf-mutator-example/test.proto
Normal file
7
custom_mutators/libprotobuf-mutator-example/test.proto
Normal file
@ -0,0 +1,7 @@
|
||||
syntax = "proto2";
|
||||
|
||||
message TEST {
|
||||
required uint32 a = 1;
|
||||
required string b = 2;
|
||||
}
|
||||
|
17
custom_mutators/libprotobuf-mutator-example/vuln.c
Normal file
17
custom_mutators/libprotobuf-mutator-example/vuln.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char str[100]={};
|
||||
read(0, str, 100);
|
||||
int *ptr = NULL;
|
||||
if( str[0] == '\x02' || str[0] == '\xe8') {
|
||||
*ptr = 123;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
10
custom_mutators/rust/.gitignore
vendored
Normal file
10
custom_mutators/rust/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
8
custom_mutators/rust/Cargo.toml
Normal file
8
custom_mutators/rust/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"custom_mutator-sys",
|
||||
"custom_mutator",
|
||||
"example",
|
||||
# Lain needs a nightly toolchain
|
||||
# "example_lain",
|
||||
]
|
11
custom_mutators/rust/README.md
Normal file
11
custom_mutators/rust/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Rust Custom Mutators
|
||||
|
||||
Bindings to create custom mutators in Rust.
|
||||
|
||||
These bindings are documented with rustdoc. To view the documentation run
|
||||
```cargo doc -p custom_mutator --open```.
|
||||
|
||||
A minimal example can be found in `example`. Build it using `cargo build --example example_mutator`.
|
||||
|
||||
An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`.
|
||||
Since lain requires a nightly rust toolchain, you need to set one up before you can play with it.
|
12
custom_mutators/rust/custom_mutator-sys/Cargo.toml
Normal file
12
custom_mutators/rust/custom_mutator-sys/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "custom_mutator-sys"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.56"
|
42
custom_mutators/rust/custom_mutator-sys/build.rs
Normal file
42
custom_mutators/rust/custom_mutator-sys/build.rs
Normal file
@ -0,0 +1,42 @@
|
||||
extern crate bindgen;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// this code is largely taken straight from the handbook: https://github.com/fitzgen/bindgen-tutorial-bzip2-sys
|
||||
fn main() {
|
||||
// Tell cargo to invalidate the built crate whenever the wrapper changes
|
||||
println!("cargo:rerun-if-changed=wrapper.h");
|
||||
|
||||
// The bindgen::Builder is the main entry point
|
||||
// to bindgen, and lets you build up options for
|
||||
// the resulting bindings.
|
||||
let bindings = bindgen::Builder::default()
|
||||
// The input header we would like to generate
|
||||
// bindings for.
|
||||
.header("wrapper.h")
|
||||
.whitelist_type("afl_state_t")
|
||||
.blacklist_type(r"u\d+")
|
||||
.opaque_type(r"_.*")
|
||||
.opaque_type("FILE")
|
||||
.opaque_type("in_addr(_t)?")
|
||||
.opaque_type("in_port(_t)?")
|
||||
.opaque_type("sa_family(_t)?")
|
||||
.opaque_type("sockaddr_in(_t)?")
|
||||
.opaque_type("time_t")
|
||||
.rustfmt_bindings(true)
|
||||
.size_t_is_usize(true)
|
||||
// Tell cargo to invalidate the built crate whenever any of the
|
||||
// included header files changed.
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||
// Finish the builder and generate the bindings.
|
||||
.generate()
|
||||
// Unwrap the Result and panic on failure.
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
// Write the bindings to the $OUT_DIR/bindings.rs file.
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
5
custom_mutators/rust/custom_mutator-sys/src/lib.rs
Normal file
5
custom_mutators/rust/custom_mutator-sys/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
4
custom_mutators/rust/custom_mutator-sys/wrapper.h
Normal file
4
custom_mutators/rust/custom_mutator-sys/wrapper.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include "../../../include/afl-fuzz.h"
|
||||
#include "../../../include/common.h"
|
||||
#include "../../../include/config.h"
|
||||
#include "../../../include/debug.h"
|
13
custom_mutators/rust/custom_mutator/Cargo.toml
Normal file
13
custom_mutators/rust/custom_mutator/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "custom_mutator"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
afl_internals = ["custom_mutator-sys"]
|
||||
|
||||
[dependencies]
|
||||
custom_mutator-sys = { path = "../custom_mutator-sys", optional=true }
|
634
custom_mutators/rust/custom_mutator/src/lib.rs
Normal file
634
custom_mutators/rust/custom_mutator/src/lib.rs
Normal file
@ -0,0 +1,634 @@
|
||||
//! Somewhat safe and somewhat ergonomic bindings for creating [AFL++](https://github.com/AFLplusplus/AFLplusplus) [custom mutators](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/custom_mutators.md) in Rust.
|
||||
//!
|
||||
//! # Usage
|
||||
//! AFL++ custom mutators are expected to be dynamic libraries which expose a set of symbols.
|
||||
//! Check out [`CustomMutator`] to see which functions of the API are supported.
|
||||
//! Then use [`export_mutator`] to export the correct symbols for your mutator.
|
||||
//! In order to use the mutator, your crate needs to be a library crate and have a `crate-type` of `cdylib`.
|
||||
//! Putting
|
||||
//! ```yaml
|
||||
//! [lib]
|
||||
//! crate-type = ["cdylib"]
|
||||
//! ```
|
||||
//! into your `Cargo.toml` should do the trick.
|
||||
//! The final executable can be found in `target/(debug|release)/your_crate_name.so`.
|
||||
//! # Example
|
||||
//! See [`export_mutator`] for an example.
|
||||
//!
|
||||
//! # On `panic`s
|
||||
//! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
|
||||
//!
|
||||
//! # Access to AFL++ internals
|
||||
//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
|
||||
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
|
||||
//!
|
||||
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
|
||||
use std::{ffi::CStr, fmt::Debug};
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
#[doc(hidden)]
|
||||
pub use custom_mutator_sys::afl_state;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[doc(hidden)]
|
||||
pub trait RawCustomMutator {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: c_uint) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Option<&'b [u8]>;
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn queue_new_entry(&mut self, filename_new_queue: &CStr, _filename_orig_queue: Option<&CStr>) {}
|
||||
|
||||
fn queue_get(&mut self, filename: &CStr) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Option<&CStr> {
|
||||
None
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Option<&CStr> {
|
||||
None
|
||||
}
|
||||
|
||||
/*fn post_process(&self, buffer: &[u8], unsigned char **out_buf)-> usize;
|
||||
int afl_custom_init_trim(&self, buffer: &[u8]);
|
||||
size_t afl_custom_trim(&self, unsigned char **out_buf);
|
||||
int afl_custom_post_trim(&self, unsigned char success);
|
||||
size_t afl_custom_havoc_mutation(&self, buffer: &[u8], unsigned char **out_buf, size_t max_size);
|
||||
unsigned char afl_custom_havoc_mutation_probability(&self);*/
|
||||
}
|
||||
|
||||
/// Wrappers for the custom mutator which provide the bridging between the C API and CustomMutator.
|
||||
/// These wrappers are not intended to be used directly, rather export_mutator will use them to publish the custom mutator C API.
|
||||
#[doc(hidden)]
|
||||
pub mod wrappers {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
use custom_mutator_sys::afl_state;
|
||||
|
||||
use core::slice;
|
||||
use std::{
|
||||
any::Any,
|
||||
convert::TryInto,
|
||||
ffi::{c_void, CStr},
|
||||
mem::ManuallyDrop,
|
||||
os::raw::c_char,
|
||||
panic::catch_unwind,
|
||||
process::abort,
|
||||
ptr::null,
|
||||
};
|
||||
|
||||
use crate::RawCustomMutator;
|
||||
|
||||
/// A structure to be used as the data pointer for our custom mutator. This was used as additional storage and is kept for now in case its needed later.
|
||||
/// Also has some convenience functions for FFI conversions (from and to ptr) and tries to make misuse hard (see [`FFIContext::from`]).
|
||||
struct FFIContext<M: RawCustomMutator> {
|
||||
mutator: M,
|
||||
}
|
||||
|
||||
impl<M: RawCustomMutator> FFIContext<M> {
|
||||
fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
|
||||
assert!(!ptr.is_null());
|
||||
ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
|
||||
}
|
||||
|
||||
fn into_ptr(self: Box<Self>) -> *const c_void {
|
||||
Box::into_raw(self) as *const c_void
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn new(afl: &'static afl_state, seed: u32) -> Box<Self> {
|
||||
Box::new(Self {
|
||||
mutator: M::init(afl, seed),
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn new(seed: u32) -> Box<Self> {
|
||||
Box::new(Self {
|
||||
mutator: M::init(seed),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// panic handler called for every panic
|
||||
fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
|
||||
use std::ops::Deref;
|
||||
let cause = panic_info
|
||||
.downcast_ref::<String>()
|
||||
.map(String::deref)
|
||||
.unwrap_or_else(|| {
|
||||
panic_info
|
||||
.downcast_ref::<&str>()
|
||||
.copied()
|
||||
.unwrap_or("<cause unknown>")
|
||||
});
|
||||
eprintln!("A panic occurred at {}: {}", method, cause);
|
||||
abort()
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
|
||||
match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_init", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
#[cfg(feature = "afl_internals")]
|
||||
pub fn afl_custom_init_<M: RawCustomMutator>(
|
||||
afl: Option<&'static afl_state>,
|
||||
seed: u32,
|
||||
) -> *const c_void {
|
||||
match catch_unwind(|| {
|
||||
let afl = afl.expect("mutator func called with NULL afl");
|
||||
FFIContext::<M>::new(afl, seed).into_ptr()
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_init", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_fuzz_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
add_buf: *mut u8,
|
||||
add_buf_size: usize,
|
||||
max_size: usize,
|
||||
) -> usize {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if buf.is_null() {
|
||||
panic!("null buf passed to afl_custom_fuzz")
|
||||
}
|
||||
if out_buf.is_null() {
|
||||
panic!("null out_buf passed to afl_custom_fuzz")
|
||||
}
|
||||
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
|
||||
let add_buff_slice = if add_buf.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(slice::from_raw_parts(add_buf, add_buf_size))
|
||||
};
|
||||
match context
|
||||
.mutator
|
||||
.fuzz(buff_slice, add_buff_slice, max_size.try_into().unwrap())
|
||||
{
|
||||
Some(buffer) => {
|
||||
*out_buf = buffer.as_ptr();
|
||||
buffer.len().try_into().unwrap()
|
||||
}
|
||||
None => {
|
||||
// return the input buffer with 0-length to let AFL skip this mutation attempt
|
||||
*out_buf = buf;
|
||||
0
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_fuzz", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_fuzz_count_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
buf: *const u8,
|
||||
buf_size: usize,
|
||||
) -> u32 {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if buf.is_null() {
|
||||
panic!("null buf passed to afl_custom_fuzz")
|
||||
}
|
||||
let buf_slice = slice::from_raw_parts(buf, buf_size);
|
||||
// see https://doc.rust-lang.org/nomicon/borrow-splitting.html
|
||||
let ctx = &mut **context;
|
||||
let mutator = &mut ctx.mutator;
|
||||
mutator.fuzz_count(buf_slice)
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_fuzz_count", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
filename_new_queue: *const c_char,
|
||||
filename_orig_queue: *const c_char,
|
||||
) {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if filename_new_queue.is_null() {
|
||||
panic!("received null filename_new_queue in afl_custom_queue_new_entry");
|
||||
}
|
||||
let filename_new_queue = unsafe { CStr::from_ptr(filename_new_queue) };
|
||||
let filename_orig_queue = if !filename_orig_queue.is_null() {
|
||||
Some(unsafe { CStr::from_ptr(filename_orig_queue) })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
context
|
||||
.mutator
|
||||
.queue_new_entry(filename_new_queue, filename_orig_queue);
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_queue_new_entry", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub unsafe fn afl_custom_deinit_<M: RawCustomMutator>(data: *mut c_void) {
|
||||
match catch_unwind(|| {
|
||||
// drop the context
|
||||
ManuallyDrop::into_inner(FFIContext::<M>::from(data));
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_deinit", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_introspection_<M: RawCustomMutator>(data: *mut c_void) -> *const c_char {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if let Some(res) = context.mutator.introspection() {
|
||||
res.as_ptr()
|
||||
} else {
|
||||
null()
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_introspection", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_describe_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
max_description_len: usize,
|
||||
) -> *const c_char {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
if let Some(res) = context.mutator.describe(max_description_len) {
|
||||
res.as_ptr()
|
||||
} else {
|
||||
null()
|
||||
}
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_describe", err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal function used in the macro
|
||||
pub fn afl_custom_queue_get_<M: RawCustomMutator>(
|
||||
data: *mut c_void,
|
||||
filename: *const c_char,
|
||||
) -> u8 {
|
||||
match catch_unwind(|| {
|
||||
let mut context = FFIContext::<M>::from(data);
|
||||
assert!(!filename.is_null());
|
||||
|
||||
context
|
||||
.mutator
|
||||
.queue_get(unsafe { CStr::from_ptr(filename) }) as u8
|
||||
}) {
|
||||
Ok(ret) => ret,
|
||||
Err(err) => panic_handler("afl_custom_queue_get", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// exports the given Mutator as a custom mutator as the C interface that AFL++ expects.
|
||||
/// It is not possible to call this macro multiple times, because it would define the custom mutator symbols multiple times.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate custom_mutator;
|
||||
/// # #[cfg(feature = "afl_internals")]
|
||||
/// # use custom_mutator::afl_state;
|
||||
/// # use custom_mutator::CustomMutator;
|
||||
/// struct MyMutator;
|
||||
/// impl CustomMutator for MyMutator {
|
||||
/// /// ...
|
||||
/// # type Error = ();
|
||||
/// # #[cfg(feature = "afl_internals")]
|
||||
/// # fn init(_afl_state: &afl_state, _seed: u32) -> Result<Self,()> {unimplemented!()}
|
||||
/// # #[cfg(not(feature = "afl_internals"))]
|
||||
/// # fn init(_seed: u32) -> Result<Self, Self::Error> {unimplemented!()}
|
||||
/// # fn fuzz<'b,'s:'b>(&'s mut self, _buffer: &'b mut [u8], _add_buff: Option<&[u8]>, _max_size: usize) -> Result<Option<&'b [u8]>, Self::Error> {unimplemented!()}
|
||||
/// }
|
||||
/// export_mutator!(MyMutator);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! export_mutator {
|
||||
($mutator_type:ty) => {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
afl: ::std::option::Option<&'static $crate::afl_state>,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_init(
|
||||
_afl: *const ::std::os::raw::c_void,
|
||||
seed: ::std::os::raw::c_uint,
|
||||
) -> *const ::std::os::raw::c_void {
|
||||
$crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_fuzz_count(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
buf: *const u8,
|
||||
buf_size: usize,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
$crate::wrappers::afl_custom_fuzz_count_::<$mutator_type>(data, buf, buf_size)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_fuzz(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
buf: *mut u8,
|
||||
buf_size: usize,
|
||||
out_buf: *mut *const u8,
|
||||
add_buf: *mut u8,
|
||||
add_buf_size: usize,
|
||||
max_size: usize,
|
||||
) -> usize {
|
||||
unsafe {
|
||||
$crate::wrappers::afl_custom_fuzz_::<$mutator_type>(
|
||||
data,
|
||||
buf,
|
||||
buf_size,
|
||||
out_buf,
|
||||
add_buf,
|
||||
add_buf_size,
|
||||
max_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_queue_new_entry(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
filename_new_queue: *const ::std::os::raw::c_char,
|
||||
filename_orig_queue: *const ::std::os::raw::c_char,
|
||||
) {
|
||||
$crate::wrappers::afl_custom_queue_new_entry_::<$mutator_type>(
|
||||
data,
|
||||
filename_new_queue,
|
||||
filename_orig_queue,
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_queue_get(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
filename: *const ::std::os::raw::c_char,
|
||||
) -> u8 {
|
||||
$crate::wrappers::afl_custom_queue_get_::<$mutator_type>(data, filename)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_introspection(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
) -> *const ::std::os::raw::c_char {
|
||||
$crate::wrappers::afl_custom_introspection_::<$mutator_type>(data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_describe(
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
max_description_len: usize,
|
||||
) -> *const ::std::os::raw::c_char {
|
||||
$crate::wrappers::afl_custom_describe_::<$mutator_type>(data, max_description_len)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn afl_custom_deinit(data: *mut ::std::os::raw::c_void) {
|
||||
unsafe { $crate::wrappers::afl_custom_deinit_::<$mutator_type>(data) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// this sanity test is supposed to just find out whether an empty mutator being exported by the macro compiles
|
||||
mod sanity_test {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
use super::afl_state;
|
||||
|
||||
use super::{export_mutator, RawCustomMutator};
|
||||
|
||||
struct ExampleMutator;
|
||||
|
||||
impl RawCustomMutator for ExampleMutator {
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(_afl: &afl_state, _seed: u32) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(_seed: u32) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_buffer: &'b mut [u8],
|
||||
_add_buff: Option<&[u8]>,
|
||||
_max_size: usize,
|
||||
) -> Option<&'b [u8]> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(ExampleMutator);
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// A custom mutator.
|
||||
/// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
|
||||
pub trait CustomMutator {
|
||||
/// The error type. All methods must return the same error type.
|
||||
type Error: Debug;
|
||||
|
||||
/// The method which handles errors.
|
||||
/// By default, this method will log the error to stderr if the environment variable "`AFL_CUSTOM_MUTATOR_DEBUG`" is set and non-empty.
|
||||
/// After logging the error, execution will continue on a best-effort basis.
|
||||
///
|
||||
/// This default behaviour can be customized by implementing this method.
|
||||
fn handle_error(err: Self::Error) {
|
||||
if std::env::var("AFL_CUSTOM_MUTATOR_DEBUG")
|
||||
.map(|v| !v.is_empty())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
eprintln!("Error in custom mutator: {:?}", err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> Result<u32, Self::Error> {
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, Self::Error>;
|
||||
|
||||
fn queue_new_entry(
|
||||
&mut self,
|
||||
filename_new_queue: &CStr,
|
||||
filename_orig_queue: Option<&CStr>,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn queue_get(&mut self, filename: &CStr) -> Result<bool, Self::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Result<Option<&CStr>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Result<Option<&CStr>, Self::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> RawCustomMutator for M
|
||||
where
|
||||
M: CustomMutator,
|
||||
M::Error: Debug,
|
||||
{
|
||||
#[cfg(feature = "afl_internals")]
|
||||
fn init(afl: &'static afl_state, seed: u32) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match Self::init(afl, seed) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
panic!("Error in afl_custom_init")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "afl_internals"))]
|
||||
fn init(seed: u32) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match Self::init(seed) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
panic!("Error in afl_custom_init")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz_count(&mut self, buffer: &[u8]) -> u32 {
|
||||
match self.fuzz_count(buffer) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Option<&'b [u8]> {
|
||||
match self.fuzz(buffer, add_buff, max_size) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_new_entry(&mut self, filename_new_queue: &CStr, filename_orig_queue: Option<&CStr>) {
|
||||
match self.queue_new_entry(filename_new_queue, filename_orig_queue) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_get(&mut self, filename: &CStr) -> bool {
|
||||
match self.queue_get(filename) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn describe(&mut self, max_description: usize) -> Option<&CStr> {
|
||||
match self.describe(max_description) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn introspection(&mut self) -> Option<&CStr> {
|
||||
match self.introspection() {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
Self::handle_error(e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
custom_mutators/rust/example/Cargo.toml
Normal file
15
custom_mutators/rust/example/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "example_mutator"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
|
||||
[[example]]
|
||||
name = "example_mutator"
|
||||
path = "./src/example_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
49
custom_mutators/rust/example/src/example_mutator.rs
Normal file
49
custom_mutators/rust/example/src/example_mutator.rs
Normal file
@ -0,0 +1,49 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
|
||||
struct ExampleMutator;
|
||||
|
||||
impl CustomMutator for ExampleMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, Self::Error> {
|
||||
buffer.reverse();
|
||||
Ok(Some(buffer))
|
||||
}
|
||||
}
|
||||
|
||||
struct OwnBufferExampleMutator {
|
||||
own_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CustomMutator for OwnBufferExampleMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
own_buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
buffer: &'b mut [u8],
|
||||
add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, ()> {
|
||||
self.own_buffer.reverse();
|
||||
Ok(Some(self.own_buffer.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(ExampleMutator);
|
16
custom_mutators/rust/example_lain/Cargo.toml
Normal file
16
custom_mutators/rust/example_lain/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "example_lain"
|
||||
version = "0.1.0"
|
||||
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
custom_mutator = { path = "../custom_mutator" }
|
||||
lain="0.5"
|
||||
|
||||
[[example]]
|
||||
name = "example_lain"
|
||||
path = "./src/lain_mutator.rs"
|
||||
crate-type = ["cdylib"]
|
1
custom_mutators/rust/example_lain/rust-toolchain
Normal file
1
custom_mutators/rust/example_lain/rust-toolchain
Normal file
@ -0,0 +1 @@
|
||||
nightly
|
59
custom_mutators/rust/example_lain/src/lain_mutator.rs
Normal file
59
custom_mutators/rust/example_lain/src/lain_mutator.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
use lain::{
|
||||
mutator::Mutator,
|
||||
prelude::*,
|
||||
rand::{rngs::StdRng, SeedableRng},
|
||||
};
|
||||
|
||||
#[derive(Debug, Mutatable, NewFuzzed, BinarySerialize)]
|
||||
struct MyStruct {
|
||||
field_1: u8,
|
||||
|
||||
#[lain(bits = 3)]
|
||||
field_2: u8,
|
||||
|
||||
#[lain(bits = 5)]
|
||||
field_3: u8,
|
||||
|
||||
#[lain(min = 5, max = 10000)]
|
||||
field_4: u32,
|
||||
|
||||
#[lain(ignore)]
|
||||
ignored_field: u64,
|
||||
}
|
||||
|
||||
struct LainMutator {
|
||||
mutator: Mutator<StdRng>,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CustomMutator for LainMutator {
|
||||
type Error = ();
|
||||
|
||||
fn init(seed: u32) -> Result<Self, ()> {
|
||||
Ok(Self {
|
||||
mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)),
|
||||
buffer: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fuzz<'b, 's: 'b>(
|
||||
&'s mut self,
|
||||
_buffer: &'b mut [u8],
|
||||
_add_buff: Option<&[u8]>,
|
||||
max_size: usize,
|
||||
) -> Result<Option<&'b [u8]>, ()> {
|
||||
// we just sample an instance of MyStruct, ignoring the current input
|
||||
let instance = MyStruct::new_fuzzed(&mut self.mutator, None);
|
||||
let size = instance.serialized_size();
|
||||
if size > max_size {
|
||||
return Err(());
|
||||
}
|
||||
self.buffer.clear();
|
||||
self.buffer.reserve(size);
|
||||
instance.binary_serialize::<_, BigEndian>(&mut self.buffer);
|
||||
Ok(Some(self.buffer.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
export_mutator!(LainMutator);
|
@ -9,6 +9,77 @@ 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 ++3.10c (release)
|
||||
- Mac OS ARM64 support
|
||||
- Android support fixed and updated by Joey Jiaojg - thanks!
|
||||
- New selective instrumentation option with __AFL_COVERAGE_* commands
|
||||
to be placed in the source code.
|
||||
Check out instrumentation/README.instrument_list.md
|
||||
- afl-fuzz
|
||||
- Making AFL_MAP_SIZE (mostly) obsolete - afl-fuzz now learns on
|
||||
start the target map size
|
||||
- upgraded cmplog/redqueen: solving for floating point, solving
|
||||
transformations (e.g. toupper, tolower, to/from hex, xor,
|
||||
arithmetics, etc.). This is costly hence new command line option
|
||||
`-l` that sets the intensity (values 1 to 3). Recommended is 2.
|
||||
- added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial seeds
|
||||
from `-i` or resumes (these have most likely already been done)
|
||||
- fix crash for very, very fast targets+systems (thanks to mhlakhani
|
||||
for reporting)
|
||||
- on restarts (`-i`)/autoresume (AFL_AUTORESUME) the stats are now
|
||||
reloaded and used, thanks to Vimal Joseph for this patch!
|
||||
- changed the meaning of '+' of the '-t' option, it now means to
|
||||
auto-calculate the timeout with the value given being the max
|
||||
timeout. The original meaning of skipping timeouts instead of
|
||||
abort is now inherent to the -t option.
|
||||
- if deterministic mode is active (`-D`, or `-M` without `-d`) then
|
||||
we sync after every queue entry as this can take very long time
|
||||
otherwise
|
||||
- added minimum SYNC_TIME to include/config.h (30 minutes default)
|
||||
- better detection if a target needs a large shared map
|
||||
- fix for `-Z`
|
||||
- fixed a few crashes
|
||||
- switched to an even faster RNG
|
||||
- added hghwng's patch for faster trace map analysis
|
||||
- printing suggestions for mistyped `AFL_` env variables
|
||||
- added Rust bindings for custom mutators (thanks @julihoh)
|
||||
- afl-cc
|
||||
- allow instrumenting LLVMFuzzerTestOneInput
|
||||
- fixed endless loop for allow/blocklist lines starting with a
|
||||
comment (thanks to Zherya for reporting)
|
||||
- cmplog/redqueen now also tracks floating point, _ExtInt() + 128bit
|
||||
- cmplog/redqueen can now process basic libc++ and libstdc++
|
||||
std::string comparisons (no position or length type variants)
|
||||
- added support for __afl_coverage_interesting() for LTO and our
|
||||
own PCGUARD (llvm 10.0.1+), read more about this function and
|
||||
selective coverage in instrumentation/README.instrument_list.md
|
||||
- added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard
|
||||
support (less performant than our own), GCC for old afl-gcc and
|
||||
CLANG for old afl-clang
|
||||
- fixed a potential crash in the LAF feature
|
||||
- workaround for llvm bitcast lto bug
|
||||
- workaround for llvm 13
|
||||
- qemuafl
|
||||
- QASan (address sanitizer for Qemu) ported to qemuafl!
|
||||
See qemu_mode/libqasan/README.md
|
||||
- solved some persistent mode bugs (thanks Dil4rd)
|
||||
- solved an issue when dumping the memory maps (thanks wizche)
|
||||
- Android support for QASan
|
||||
- unicornafl
|
||||
- Substantial speed gains in python bindings for certain use cases
|
||||
- Improved rust bindings
|
||||
- Added a new example harness to compare python, c and rust bindings
|
||||
- afl-cmin and afl-showmap now support the -f option
|
||||
- afl_plot now also generates a graph on the discovered edges
|
||||
- changed default: no memory limit for afl-cmin and afl-cmin.bash
|
||||
- warn on any _AFL and __AFL env vars.
|
||||
- set AFL_IGNORE_UNKNOWN_ENVS to not warn on unknown AFL_... env vars
|
||||
- added dummy Makefile to instrumentation/
|
||||
- Updated utils/afl_frida to be 5% faster, 7% on x86_x64
|
||||
- Added `AFL_KILL_SIGNAL` env variable (thanks @v-p-b)
|
||||
- @Edznux added a nice documentation on how to use rpc.statsd with
|
||||
afl++ in docs/rpc_statsd.md, thanks!
|
||||
|
||||
### Version ++3.00c (release)
|
||||
- llvm_mode/ and gcc_plugin/ moved to instrumentation/
|
||||
- examples/ renamed to utils/
|
||||
@ -46,6 +117,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
- somewhere we broke -n dumb fuzzing, fixed
|
||||
- added afl_custom_describe to the custom mutator API to allow for easy
|
||||
mutation reproduction on crashing inputs
|
||||
- new env. var. AFL_NO_COLOR (or AFL_NO_COLOUR) to suppress colored
|
||||
console output (when configured with USE_COLOR and not ALWAYS_COLORED)
|
||||
- instrumentation
|
||||
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
||||
very much!!
|
||||
|
@ -174,7 +174,7 @@
|
||||
|
||||
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
||||
used for getting basic block information at runtime.
|
||||
Pintool is only available for Intel x32/x64 on Linux, Mac OS and Windows
|
||||
Pintool is only available for Intel x32/x64 on Linux, Mac OS and Windows,
|
||||
whereas Dynamorio is additionally available for ARM and AARCH64.
|
||||
Dynamorio is also 10x faster than Pintool.
|
||||
|
||||
@ -182,7 +182,7 @@
|
||||
Dynamorio has a speed decrease of 98-99%
|
||||
Pintool has a speed decrease of 99.5%
|
||||
|
||||
Hence Dynamorio is the option to go for if everything fails, and Pintool
|
||||
Hence Dynamorio is the option to go for if everything else fails, and Pintool
|
||||
only if Dynamorio fails too.
|
||||
|
||||
Dynamorio solutions:
|
||||
@ -205,6 +205,7 @@
|
||||
* QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
|
||||
* Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
|
||||
* S2E: [https://github.com/S2E](https://github.com/S2E)
|
||||
* Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only)
|
||||
* ... please send me any missing that are good
|
||||
|
||||
|
||||
|
@ -4,6 +4,11 @@ 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.
|
||||
|
||||
There is also experimental support for Rust in `custom_mutators/rust`.
|
||||
Please refer to that directory for documentation.
|
||||
Run ```cargo doc -p custom_mutator --open``` in that directory to view the
|
||||
documentation in your web browser.
|
||||
|
||||
Implemented by
|
||||
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
||||
- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
|
||||
|
122
docs/docs.md
Normal file
122
docs/docs.md
Normal file
@ -0,0 +1,122 @@
|
||||
# Restructure afl++'s documentation
|
||||
|
||||
## About us
|
||||
|
||||
We are dedicated to everything around fuzzing, our main and most well known
|
||||
contribution is the fuzzer `afl++` which is part of all major Unix
|
||||
distributions (e.g. Debian, Arch, FreeBSD, etc.) and is deployed on Google's
|
||||
oss-fuzz and clusterfuzz. It is rated the top fuzzer on Google's fuzzbench.
|
||||
|
||||
We are four individuals from Europe supported by a large community.
|
||||
|
||||
All our tools are open source.
|
||||
|
||||
## About the afl++ fuzzer project
|
||||
|
||||
afl++ inherited it's documentation from the original Google afl project.
|
||||
Since then it has been massively improved - feature and performance wise -
|
||||
and although the documenation has likewise been continued it has grown out
|
||||
of proportion.
|
||||
The documentation is done by non-natives to the English language, plus
|
||||
none of us has a writer background.
|
||||
|
||||
We see questions on afl++ usage on mailing lists (e.g. afl-users), discord
|
||||
channels, web forums and as issues in our repository.
|
||||
|
||||
This only increases as afl++ has been on the top of Google's fuzzbench
|
||||
statistics (which measures the performance of fuzzers) and is now being
|
||||
integrated in Google's oss-fuzz and clusterfuzz - and is in many Unix
|
||||
packaging repositories, e.g. Debian, FreeBSD, etc.
|
||||
|
||||
afl++ now has 44 (!) documentation files with 13k total lines of content.
|
||||
This is way too much.
|
||||
|
||||
Hence afl++ needs a complete overhaul of it's documentation, both on a
|
||||
organisation/structural level as well as the content.
|
||||
|
||||
Overall the following actions have to be performed:
|
||||
* Create a better structure of documentation so it is easier to find the
|
||||
information that is being looked for, combining and/or splitting up the
|
||||
existing documents as needed.
|
||||
* Rewrite some documentation to remove duplication. Several information is
|
||||
present several times in the documentation. These should be removed to
|
||||
where needed so that we have as little bloat as possible.
|
||||
* The documents have been written and modified by a lot of different people,
|
||||
most of them non-native English speaker. Hence an overall review where
|
||||
parts should be rewritten has to be performed and then the rewrite done.
|
||||
* Create a cheat-sheet for a very short best-setup build and run of afl++
|
||||
* Pictures explain more than 1000 words. We need at least 4 images that
|
||||
explain the workflow with afl++:
|
||||
- the build workflow
|
||||
- the fuzzing workflow
|
||||
- the fuzzing campaign management workflow
|
||||
- the overall workflow that is an overview of the above
|
||||
- maybe more? where the technical writes seems it necessary for
|
||||
understanding.
|
||||
|
||||
Requirements:
|
||||
* Documentation has to be in Markdown format
|
||||
* Images have to be either in SVG or PNG format.
|
||||
* All documentation should be (moved) in(to) docs/
|
||||
|
||||
The project does not require writing new documentation or tutorials beside the
|
||||
cheat sheet. The technical information for the cheat sheet will be provided by
|
||||
us.
|
||||
|
||||
## Metrics
|
||||
|
||||
afl++ is a the highest performant fuzzer publicly available - but is also the
|
||||
most feature rich and complex. With the publicity of afl++' success and
|
||||
deployment in Google projects internally and externally and availability as
|
||||
a package on most Linux distributions we see more and more issues being
|
||||
created and help requests on our Discord channel that would not be
|
||||
necessary if people would have read through all our documentation - which
|
||||
is unrealistic.
|
||||
|
||||
We expect the the new documenation after this project to be cleaner, easier
|
||||
accessible and lighter to digest by our users, resulting in much less
|
||||
help requests. On the other hand the amount of users using afl++ should
|
||||
increase as well as it will be more accessible which would also increase
|
||||
questions again - but overall resulting in a reduction of help requests.
|
||||
|
||||
In numbers: we currently have per week on average 5 issues on Github,
|
||||
10 questions on discord and 1 on mailing lists that would not be necessary
|
||||
with perfect documentation and perfect people.
|
||||
|
||||
We would consider this project a success if afterwards we only have
|
||||
2 issues on Github and 3 questions on discord anymore that would be answered
|
||||
by reading the documentation. The mailing list is usually used by the most
|
||||
novice users and we don't expect any less questions there.
|
||||
|
||||
## Project Budget
|
||||
|
||||
We have zero experience with technical writers, so this is very hard for us
|
||||
to calculate. We expect it to be a lot of work though because of the amount
|
||||
of documentation we have that needs to be restructured and partially rewritten
|
||||
(44 documents with 13k total lines of content).
|
||||
|
||||
We assume the daily rate of a very good and experienced technical writer in
|
||||
times of a pandemic to be ~500$ (according to web research), and calculate
|
||||
the overall amout of work to be around 20 days for everything incl. the
|
||||
graphics (but again - this is basically just guessing).
|
||||
|
||||
Technical Writer 10000$
|
||||
Volunteer stipends 0$ (waved)
|
||||
T-Shirts for the top 10 contributors and helpers to this documentation project:
|
||||
10 afl++ logo t-shirts 20$ each 200$
|
||||
10 shipping cost of t-shirts 10$ each 100$
|
||||
|
||||
Total: 10.300$
|
||||
(in the submission form 10.280$ was entered)
|
||||
|
||||
## Additional Information
|
||||
|
||||
We have participated in Google Summer of Code in 2020 and hope to be selected
|
||||
again in 2021.
|
||||
|
||||
We have no experience with a technical writer, but we will support that person
|
||||
with video calls, chats, emails and messaging, provide all necessary information
|
||||
and write technical contents that is required for the success of this project.
|
||||
It is clear to us that a technical writer knows how to write, but cannot know
|
||||
the technical details in a complex tooling like in afl++. This guidance, input,
|
||||
etc. has to come from us.
|
@ -5,6 +5,10 @@
|
||||
users or for some types of custom fuzzing setups. See [README.md](README.md) for the general
|
||||
instruction manual.
|
||||
|
||||
Note that most tools will warn on any unknown AFL environment variables.
|
||||
This is for warning on typos that can happen. If you want to disable this
|
||||
check then set the `AFL_IGNORE_UNKNOWN_ENVS` environment variable.
|
||||
|
||||
## 1) Settings for all compilers
|
||||
|
||||
Starting with afl++ 3.0 there is only one compiler: afl-cc
|
||||
@ -18,7 +22,6 @@ To select the different instrumentation modes this can be done by
|
||||
`MODE` can be one of `LTO` (afl-clang-lto*), `LLVM` (afl-clang-fast*), `GCC_PLUGIN`
|
||||
(afl-g*-fast) or `GCC` (afl-gcc/afl-g++).
|
||||
|
||||
|
||||
Because (with the exception of the --afl-MODE command line option) the
|
||||
compile-time tools do not accept afl specific command-line options, they
|
||||
make fairly broad use of environmental variables instead:
|
||||
@ -113,11 +116,15 @@ Then there are a few specific features that are only available in instrumentatio
|
||||
|
||||
- `AFL_LLVM_INSTRUMENT` - this configures the instrumentation mode.
|
||||
Available options:
|
||||
PCGUARD - our own pcgard based instrumentation (default)
|
||||
NATIVE - clang's original pcguard based instrumentation
|
||||
CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
|
||||
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)
|
||||
GCC - outdated gcc instrumentation
|
||||
CLANG - outdated clang instrumentation
|
||||
In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
|
||||
NGRAM, seperate the options with a comma "," then, e.g.:
|
||||
`AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4`
|
||||
@ -283,6 +290,11 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
the target. This must be equal or larger than the size the target was
|
||||
compiled with.
|
||||
|
||||
- `AFL_CMPLOG_ONLY_NEW` will only perform the expensive cmplog feature for
|
||||
newly found testcases and not for testcases that are loaded on startup
|
||||
(`-i in`). This is an important feature to set when resuming a fuzzing
|
||||
session.
|
||||
|
||||
- `AFL_TESTCACHE_SIZE` allows you to override the size of `#define TESTCASE_CACHE`
|
||||
in config.h. Recommended values are 50-250MB - or more if your fuzzing
|
||||
finds a huge amount of paths for large inputs.
|
||||
@ -346,6 +358,10 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Note that `AFL_POST_LIBRARY` is deprecated, use `AFL_CUSTOM_MUTATOR_LIBRARY`
|
||||
instead (see below).
|
||||
|
||||
- `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on timeout.
|
||||
Unless you implement your own targets or instrumentation, you likely don't have to set it.
|
||||
By default, on timeout and on exit, `SIGKILL` (`AFL_KILL_SIGNAL=9`) will be delivered to the child.
|
||||
|
||||
- Setting `AFL_CUSTOM_MUTATOR_LIBRARY` to a shared library with
|
||||
afl_custom_fuzz() creates additional mutations through this library.
|
||||
If afl-fuzz is compiled with Python (which is autodetected during builing
|
||||
@ -381,6 +397,9 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
some basic stats. This behavior is also automatically triggered when the
|
||||
output from afl-fuzz is redirected to a file or to a pipe.
|
||||
|
||||
- Setting `AFL_NO_COLOR` or `AFL_NO_COLOUR` will omit control sequences for
|
||||
coloring console output when configured with USE_COLOR and not ALWAYS_COLORED.
|
||||
|
||||
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
|
||||
no valid terminal was detected (for virtual consoles)
|
||||
|
||||
@ -420,13 +439,19 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
normally done when starting up the forkserver and causes a pretty
|
||||
significant performance drop.
|
||||
|
||||
- Setting `AFL_STATSD` enable StatsD metrics collection.
|
||||
- Setting `AFL_STATSD` enables StatsD metrics collection.
|
||||
By default AFL++ will send these metrics over UDP to 127.0.0.1:8125.
|
||||
The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT`
|
||||
respectively.
|
||||
To get the most out of this, you should provide `AFL_STATSD_TAGS_FLAVOR` that
|
||||
matches your StatsD server.
|
||||
Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`.
|
||||
The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` respectively.
|
||||
To enable tags (banner and afl_version) you should provide `AFL_STATSD_TAGS_FLAVOR` that matches
|
||||
your StatsD server (see `AFL_STATSD_TAGS_FLAVOR`)
|
||||
|
||||
- Setting `AFL_STATSD_TAGS_FLAVOR` to one of `dogstatsd`, `librato`, `signalfx` or `influxdb`
|
||||
allows you to add tags to your fuzzing instances. This is especially useful when running
|
||||
multiple instances (`-M/-S` for example). Applied tags are `banner` and `afl_version`.
|
||||
`banner` corresponds to the name of the fuzzer provided through `-M/-S`.
|
||||
`afl_version` corresponds to the currently running afl version (e.g `++3.0c`).
|
||||
Default (empty/non present) will add no tags to the metrics.
|
||||
See [rpc_statsd.md](rpc_statsd.md) for more information.
|
||||
|
||||
- Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash.
|
||||
For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting
|
||||
@ -493,6 +518,12 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
stack pointer in which QEMU can find the return address when `start addr` is
|
||||
hit.
|
||||
|
||||
- With `AFL_USE_QASAN` you can enable QEMU AddressSanitizer for dynamically
|
||||
linked binaries.
|
||||
|
||||
- With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered signal
|
||||
handlers of the target.
|
||||
|
||||
## 6) Settings for afl-cmin
|
||||
|
||||
The corpus minimization script offers very little customization:
|
||||
@ -508,7 +539,7 @@ The corpus minimization script offers very little customization:
|
||||
a modest security risk on multi-user systems with rogue users, but should
|
||||
be safe on dedicated fuzzing boxes.
|
||||
|
||||
# #6) Settings for afl-tmin
|
||||
## 7) Settings for afl-tmin
|
||||
|
||||
Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
|
||||
searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a
|
||||
|
@ -3,6 +3,40 @@
|
||||
In the following, we describe a variety of ideas that could be implemented
|
||||
for future AFL++ versions.
|
||||
|
||||
# GSoC 2021
|
||||
|
||||
All GSoC 2021 projects will be in the Rust development language!
|
||||
|
||||
## UI for libaflrs
|
||||
|
||||
Write a user interface to libaflrs, the upcoming backend of afl++.
|
||||
This might look like the afl-fuzz UI, but you can improve on it - and should!
|
||||
|
||||
## Schedulers for libaflrs
|
||||
|
||||
Schedulers is a mechanism that selects items from the fuzzing corpus based
|
||||
on strategy and randomness. One scheduler might focus on long paths,
|
||||
another on rarity of edges disocvered, still another on a combination on
|
||||
things. Some of the schedulers in afl++ have to be ported, but you are free
|
||||
to come up with your own if you want to - and see how it performs.
|
||||
|
||||
## Forkserver support for libaflrs
|
||||
|
||||
The current libaflrs implementation fuzzes in-memory, however obviously we
|
||||
want to support afl instrumented binaries as well.
|
||||
Hence a forkserver support needs to be implemented - forking off the target
|
||||
and talking to the target via a socketpair and the communication protocol
|
||||
within.
|
||||
|
||||
## More Observers for libaflrs
|
||||
|
||||
An observer is measuring functionality that looks at the target being fuzzed
|
||||
and documents something about it. In traditional fuzzing this is the coverage
|
||||
in the target, however we want to add various more observers, e.g. stack depth,
|
||||
heap usage, etc. - this is a topic for an experienced Rust developer.
|
||||
|
||||
# Generic ideas and wishlist
|
||||
|
||||
## Analysis software
|
||||
|
||||
Currently analysis is done by using afl-plot, which is rather outdated.
|
||||
@ -16,6 +50,8 @@ test cases executed.
|
||||
It should be clickable which value is X and Y axis, zoom factor, log scaling
|
||||
on-off, etc.
|
||||
|
||||
Mentor: vanhauser-thc
|
||||
|
||||
## WASM Instrumentation
|
||||
|
||||
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
|
||||
@ -36,19 +72,6 @@ Either improve a single mutator thorugh learning of many different bugs
|
||||
|
||||
Mentor: domenukk
|
||||
|
||||
## Collision-free Binary-Only Maps
|
||||
|
||||
AFL++ supports collison-free maps using an LTO (link-time-optimization) pass.
|
||||
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!
|
||||
|
@ -13,8 +13,8 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ
|
||||
|
||||
| AFL flag | Power Schedule |
|
||||
| ------------- | -------------------------- |
|
||||
| `-p explore` (default)|  |
|
||||
| `-p fast` | =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) |
|
||||
| `-p explore` |  |
|
||||
| `-p fast` (default)| =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) |
|
||||
| `-p coe` |  |
|
||||
| `-p quad` |  |
|
||||
| `-p lin` |  |
|
||||
|
143
docs/rpc_statsd.md
Normal file
143
docs/rpc_statsd.md
Normal file
@ -0,0 +1,143 @@
|
||||
# Remote monitoring with StatsD
|
||||
|
||||
StatsD allows you to receive and aggregate metrics from a wide range of applications and retransmit them to the backend of your choice.
|
||||
This enables you to create nice and readable dashboards containing all the information you need on your fuzzer instances.
|
||||
No need to write your own statistics parsing system, deploy and maintain it to all your instances, sync with your graph rendering system...
|
||||
|
||||
The available metrics are :
|
||||
- cycle_done
|
||||
- cycles_wo_finds
|
||||
- execs_done
|
||||
- execs_per_sec
|
||||
- paths_total
|
||||
- paths_favored
|
||||
- paths_found
|
||||
- paths_imported
|
||||
- max_depth
|
||||
- cur_path
|
||||
- pending_favs
|
||||
- pending_total
|
||||
- variable_paths
|
||||
- unique_crashes
|
||||
- unique_hangs
|
||||
- total_crashes
|
||||
- slowest_exec_ms
|
||||
- edges_found
|
||||
- var_byte_count
|
||||
- havoc_expansion
|
||||
|
||||
Compared to the default integrated UI, these metrics give you the opportunity to visualize trends and fuzzing state over time.
|
||||
By doing so, you might be able to see when the fuzzing process has reached a state of no progress, visualize what are the "best strategies"
|
||||
(according to your own criteria) for your targets, etc. And doing so without requiring to log into each instance manually.
|
||||
|
||||
An example visualisation may look like the following:
|
||||

|
||||
|
||||
*Notes: The exact same dashboard can be imported with [this JSON template](statsd/grafana-afl++.json).*
|
||||
|
||||
## How to use
|
||||
|
||||
To enable the StatsD reporting on your fuzzer instances, you need to set the environment variable `AFL_STATSD=1`.
|
||||
|
||||
Setting `AFL_STATSD_TAGS_FLAVOR` to the provider of your choice will assign tags / labels to each metric based on their format.
|
||||
The possible values are `dogstatsd`, `librato`, `signalfx` or `influxdb`.
|
||||
For more information on these env vars, check out `docs/env_variables.md`.
|
||||
|
||||
The simplest way of using this feature is to use any metric provider and change the host/port of your StatsD daemon,
|
||||
with `AFL_STATSD_HOST` and `AFL_STATSD_PORT`, if required (defaults are `localhost` and port `8125`).
|
||||
To get started, here are some instructions with free and open source tools.
|
||||
The following setup is based on Prometheus, statsd_exporter and Grafana.
|
||||
Grafana here is not mandatory, but gives you some nice graphs and features.
|
||||
|
||||
Depending on your setup and infrastructure, you may want to run these applications not on your fuzzer instances.
|
||||
Only one instance of these 3 application is required for all your fuzzers.
|
||||
|
||||
To simplify everything, we will use Docker and docker-compose.
|
||||
Make sure you have them both installed. On most common Linux distributions, it's as simple as:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sh get-docker.sh
|
||||
```
|
||||
|
||||
Once that's done, we can create the infrastructure.
|
||||
Create and move into the directory of your choice. This will store all the configurations files required.
|
||||
|
||||
First, create a `docker-compose.yml` containing the following:
|
||||
```yml
|
||||
version: '3'
|
||||
|
||||
networks:
|
||||
statsd-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus
|
||||
container_name: prometheus
|
||||
volumes:
|
||||
- ./prometheus.yml:/prometheus.yml
|
||||
command:
|
||||
- '--config.file=/prometheus.yml'
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9090:9090"
|
||||
networks:
|
||||
- statsd-net
|
||||
|
||||
statsd_exporter:
|
||||
image: prom/statsd-exporter
|
||||
container_name: statsd_exporter
|
||||
volumes:
|
||||
- ./statsd_mapping.yml:/statsd_mapping.yml
|
||||
command:
|
||||
- "--statsd.mapping-config=/statsd_mapping.yml"
|
||||
ports:
|
||||
- "9102:9102/tcp"
|
||||
- "8125:9125/udp"
|
||||
networks:
|
||||
- statsd-net
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- statsd-net
|
||||
```
|
||||
|
||||
Then `prometheus.yml`
|
||||
```yml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'fuzzing_metrics'
|
||||
static_configs:
|
||||
- targets: ['statsd_exporter:9102']
|
||||
```
|
||||
|
||||
And finally `statsd_mapping.yml`
|
||||
```yml
|
||||
mappings:
|
||||
- match: "fuzzing.*"
|
||||
name: "fuzzing"
|
||||
labels:
|
||||
type: "$1"
|
||||
```
|
||||
|
||||
Run `docker-compose up -d`.
|
||||
|
||||
Everything should now be setup, you are now able to run your fuzzers with
|
||||
|
||||
```
|
||||
AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -M test-fuzzer-1 -i i -o o ./bin/my-application @@
|
||||
AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -S test-fuzzer-2 -i i -o o ./bin/my-application @@
|
||||
...
|
||||
```
|
||||
|
||||
This setup may be modified before use in a production environment. Depending on your needs: adding passwords, creating volumes for storage,
|
||||
tweaking the metrics gathering to get host metrics (CPU, RAM ...).
|
1816
docs/statsd/grafana-afl++.json
Normal file
1816
docs/statsd/grafana-afl++.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,13 +29,18 @@ With that out of the way, let's talk about what's actually on the screen...
|
||||
|
||||
### The status bar
|
||||
|
||||
```
|
||||
american fuzzy lop ++3.01a (default) [fast] {0}
|
||||
```
|
||||
|
||||
The top line shows you which mode afl-fuzz is running in
|
||||
(normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode")
|
||||
and the version of afl++.
|
||||
Next to the version is the banner, which, if not set with -T by hand, will
|
||||
either show the binary name being fuzzed, or the -M/-S main/secondary name for
|
||||
parallel fuzzing.
|
||||
Finally, the last item is the power schedule mode being run (default: explore).
|
||||
Second to last is the power schedule mode being run (default: fast).
|
||||
Finally, the last item is the CPU id.
|
||||
|
||||
### Process timing
|
||||
|
||||
|
BIN
docs/visualization/statsd-grafana.png
Normal file
BIN
docs/visualization/statsd-grafana.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
@ -37,10 +37,6 @@
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
@ -134,17 +130,34 @@
|
||||
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
|
||||
#define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf)
|
||||
|
||||
#ifdef WORD_SIZE_64
|
||||
#define AFL_RAND_RETURN u64
|
||||
#else
|
||||
#define AFL_RAND_RETURN u32
|
||||
#endif
|
||||
|
||||
extern s8 interesting_8[INTERESTING_8_LEN];
|
||||
extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
|
||||
extern s32
|
||||
interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN];
|
||||
|
||||
struct tainted {
|
||||
|
||||
u32 pos;
|
||||
u32 len;
|
||||
struct tainted *next;
|
||||
struct tainted *prev;
|
||||
|
||||
};
|
||||
|
||||
struct queue_entry {
|
||||
|
||||
u8 *fname; /* File name for the test case */
|
||||
u32 len; /* Input length */
|
||||
u32 id; /* entry number in queue_buf */
|
||||
|
||||
u8 cal_failed; /* Calibration failed? */
|
||||
u8 colorized, /* Do not run redqueen stage again */
|
||||
cal_failed; /* Calibration failed? */
|
||||
bool trim_done, /* Trimmed? */
|
||||
was_fuzzed, /* historical, but needed for MOpt */
|
||||
passed_det, /* Deterministic stages passed? */
|
||||
@ -152,7 +165,6 @@ struct queue_entry {
|
||||
var_behavior, /* Variable behavior? */
|
||||
favored, /* Currently favored? */
|
||||
fs_redundant, /* Marked as redundant in the fs? */
|
||||
fully_colorized, /* Do not run redqueen stage again */
|
||||
is_ascii, /* Is the input just ascii text? */
|
||||
disabled; /* Is disabled from fuzz selection */
|
||||
|
||||
@ -168,12 +180,19 @@ struct queue_entry {
|
||||
u8 *trace_mini; /* Trace bytes, if kept */
|
||||
u32 tc_ref; /* Trace bytes ref count */
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
u32 bitsmap_size;
|
||||
#endif
|
||||
|
||||
double perf_score, /* performance score */
|
||||
weight;
|
||||
|
||||
u8 *testcase_buf; /* The testcase buffer, if loaded. */
|
||||
|
||||
struct queue_entry *next; /* Next element, if any */
|
||||
u8 * cmplog_colorinput; /* the result buf of colorization */
|
||||
struct tainted *taint; /* Taint information from CmpLog */
|
||||
|
||||
struct queue_entry *mother; /* queue entry this based on */
|
||||
|
||||
};
|
||||
|
||||
@ -365,13 +384,13 @@ typedef struct afl_env_vars {
|
||||
afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
|
||||
afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
|
||||
afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
|
||||
afl_cycle_schedules, afl_expand_havoc, afl_statsd;
|
||||
afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new;
|
||||
|
||||
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
|
||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
|
||||
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
||||
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
||||
*afl_testcache_entries;
|
||||
*afl_testcache_entries, *afl_kill_signal;
|
||||
|
||||
} afl_env_vars_t;
|
||||
|
||||
@ -385,7 +404,7 @@ struct afl_pass_stat {
|
||||
struct foreign_sync {
|
||||
|
||||
u8 * dir;
|
||||
time_t ctime;
|
||||
time_t mtime;
|
||||
|
||||
};
|
||||
|
||||
@ -406,7 +425,8 @@ typedef struct afl_state {
|
||||
really makes no sense to haul them around as function parameters. */
|
||||
u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
|
||||
total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key,
|
||||
most_time, most_execs_key, most_execs, old_hit_count, force_ui_update;
|
||||
most_time, most_execs_key, most_execs, old_hit_count, force_ui_update,
|
||||
prev_run_time;
|
||||
|
||||
MOpt_globals_t mopt_globals_core, mopt_globals_pilot;
|
||||
|
||||
@ -550,6 +570,7 @@ typedef struct afl_state {
|
||||
blocks_eff_total, /* Blocks subject to effector maps */
|
||||
blocks_eff_select, /* Blocks selected as fuzzable */
|
||||
start_time, /* Unix start time (ms) */
|
||||
last_sync_time, /* Time of last sync */
|
||||
last_path_time, /* Time for most recent path (ms) */
|
||||
last_crash_time, /* Time for most recent crash (ms) */
|
||||
last_hang_time; /* Time for most recent hang (ms) */
|
||||
@ -563,7 +584,7 @@ typedef struct afl_state {
|
||||
|
||||
u8 stage_name_buf[STAGE_BUF_SIZE]; /* reused stagename buf with len 64 */
|
||||
|
||||
s32 stage_cur, stage_max; /* Stage progression */
|
||||
u32 stage_cur, stage_max; /* Stage progression */
|
||||
s32 splicing_with; /* Splicing with which test case? */
|
||||
|
||||
u32 main_node_id, main_node_max; /* Main instance job splitting */
|
||||
@ -580,8 +601,9 @@ typedef struct afl_state {
|
||||
|
||||
u32 rand_cnt; /* Random number counter */
|
||||
|
||||
u64 rand_seed[4];
|
||||
s64 init_seed;
|
||||
/* unsigned long rand_seed[3]; would also work */
|
||||
AFL_RAND_RETURN rand_seed[3];
|
||||
s64 init_seed;
|
||||
|
||||
u64 total_cal_us, /* Total calibration time (us) */
|
||||
total_cal_cycles; /* Total calibration cycles */
|
||||
@ -625,6 +647,10 @@ typedef struct afl_state {
|
||||
/* cmplog forkserver ids */
|
||||
s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
|
||||
u32 cmplog_prev_timed_out;
|
||||
u32 cmplog_max_filesize;
|
||||
u32 cmplog_lvl;
|
||||
u32 colorize_success;
|
||||
u8 cmplog_enable_arith, cmplog_enable_transform;
|
||||
|
||||
struct afl_pass_stat *pass_stats;
|
||||
struct cmp_map * orig_cmp_map;
|
||||
@ -634,10 +660,10 @@ typedef struct afl_state {
|
||||
|
||||
unsigned long long int last_avg_exec_update;
|
||||
u32 last_avg_execs;
|
||||
float last_avg_execs_saved;
|
||||
double last_avg_execs_saved;
|
||||
|
||||
/* foreign sync */
|
||||
#define FOREIGN_SYNCS_MAX 32
|
||||
#define FOREIGN_SYNCS_MAX 32U
|
||||
u8 foreign_sync_cnt;
|
||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||
|
||||
@ -728,6 +754,7 @@ typedef struct afl_state {
|
||||
char mutation[8072];
|
||||
char m_tmp[4096];
|
||||
FILE *introspection_file;
|
||||
u32 bitsmap_size;
|
||||
#endif
|
||||
|
||||
} afl_state_t;
|
||||
@ -1014,12 +1041,12 @@ void write_bitmap(afl_state_t *);
|
||||
u32 count_bits(afl_state_t *, u8 *);
|
||||
u32 count_bytes(afl_state_t *, u8 *);
|
||||
u32 count_non_255_bytes(afl_state_t *, u8 *);
|
||||
void simplify_trace(afl_state_t *, u8 *);
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#ifdef WORD_SIZE_64
|
||||
void simplify_trace(afl_state_t *, u64 *);
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
void discover_word(u8 *ret, u64 *current, u64 *virgin);
|
||||
#else
|
||||
void simplify_trace(afl_state_t *, u32 *);
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
void discover_word(u8 *ret, u32 *current, u32 *virgin);
|
||||
#endif
|
||||
void init_count_class16(void);
|
||||
void minimize_bits(afl_state_t *, u8 *, u8 *);
|
||||
@ -1028,6 +1055,7 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
|
||||
/* Extras */
|
||||
|
||||
@ -1042,9 +1070,10 @@ void destroy_extras(afl_state_t *);
|
||||
|
||||
/* Stats */
|
||||
|
||||
void load_stats_file(afl_state_t *);
|
||||
void write_setup_file(afl_state_t *, u32, char **);
|
||||
void write_stats_file(afl_state_t *, double, double, double);
|
||||
void maybe_update_plot_file(afl_state_t *, double, double);
|
||||
void write_stats_file(afl_state_t *, u32, double, double, double);
|
||||
void maybe_update_plot_file(afl_state_t *, u32, double, double);
|
||||
void show_stats(afl_state_t *);
|
||||
void show_init_stats(afl_state_t *);
|
||||
|
||||
@ -1108,11 +1137,10 @@ void read_foreign_testcases(afl_state_t *, int);
|
||||
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
|
||||
|
||||
/* RedQueen */
|
||||
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
|
||||
u64 exec_cksum);
|
||||
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len);
|
||||
|
||||
/* xoshiro256** */
|
||||
uint64_t rand_next(afl_state_t *afl);
|
||||
/* our RNG wrapper */
|
||||
AFL_RAND_RETURN rand_next(afl_state_t *afl);
|
||||
|
||||
/* probability between 0.0 and 1.0 */
|
||||
double rand_next_percent(afl_state_t *afl);
|
||||
|
@ -271,7 +271,7 @@ static inline void *DFL_ck_alloc_nozero(u32 size) {
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
ret = (char *)ret + ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
@ -311,7 +311,7 @@ static inline void DFL_ck_free(void *mem) {
|
||||
|
||||
ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
||||
|
||||
free(mem - ALLOC_OFF_HEAD);
|
||||
free((char *)mem - ALLOC_OFF_HEAD);
|
||||
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
old_size = ALLOC_S(orig);
|
||||
orig -= ALLOC_OFF_HEAD;
|
||||
orig = (char *)orig - ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_CHECK_SIZE(old_size);
|
||||
|
||||
@ -363,10 +363,11 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
if (orig) {
|
||||
|
||||
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
|
||||
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
||||
memcpy((char *)ret + ALLOC_OFF_HEAD, (char *)orig + ALLOC_OFF_HEAD,
|
||||
MIN(size, old_size));
|
||||
memset((char *)orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
||||
|
||||
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
|
||||
ALLOC_C1((char *)orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
|
||||
|
||||
free(orig);
|
||||
|
||||
@ -374,13 +375,13 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
ret = (char *)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);
|
||||
if (size > old_size) memset((char *)ret + old_size, 0, size - old_size);
|
||||
|
||||
return ret;
|
||||
|
||||
@ -401,7 +402,7 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
ret = (char *)ret + ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
|
@ -1,62 +1,34 @@
|
||||
/*
|
||||
american fuzzy lop++ - android shared memory compatibility layer
|
||||
----------------------------------------------------------------
|
||||
|
||||
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 header re-defines the shared memory routines used by AFL++
|
||||
using the Andoid API.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _ANDROID_ASHMEM_H
|
||||
#define _ANDROID_ASHMEM_H
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifndef _ANDROID_ASHMEM_H
|
||||
#define _ANDROID_ASHMEM_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#if __ANDROID_API__ >= 26
|
||||
#define shmat bionic_shmat
|
||||
#define shmctl bionic_shmctl
|
||||
#define shmdt bionic_shmdt
|
||||
#define shmget bionic_shmget
|
||||
#endif
|
||||
#if __ANDROID_API__ >= 26
|
||||
#define shmat bionic_shmat
|
||||
#define shmctl bionic_shmctl
|
||||
#define shmdt bionic_shmdt
|
||||
#define shmget bionic_shmget
|
||||
#endif
|
||||
#include <sys/shm.h>
|
||||
#undef shmat
|
||||
#undef shmctl
|
||||
#undef shmdt
|
||||
#undef shmget
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/shm.h>
|
||||
#undef shmat
|
||||
#undef shmctl
|
||||
#undef shmdt
|
||||
#undef shmget
|
||||
#include <stdio.h>
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
|
||||
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
|
||||
int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
|
||||
|
||||
int ret = 0;
|
||||
if (__cmd == IPC_RMID) {
|
||||
|
||||
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
|
||||
struct ashmem_pin pin = {0, (unsigned int)length};
|
||||
struct ashmem_pin pin = {0, length};
|
||||
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
|
||||
close(__shmid);
|
||||
|
||||
@ -66,7 +38,7 @@ static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
|
||||
|
||||
}
|
||||
|
||||
static inline int shmget(key_t __key, size_t __size, int __shmflg) {
|
||||
int shmget(key_t __key, size_t __size, int __shmflg) {
|
||||
|
||||
(void)__shmflg;
|
||||
int fd, ret;
|
||||
@ -90,7 +62,7 @@ error:
|
||||
|
||||
}
|
||||
|
||||
static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
|
||||
void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
|
||||
|
||||
(void)__shmflg;
|
||||
int size;
|
||||
@ -106,7 +78,6 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
#endif
|
||||
#endif /* !_ANDROID_ASHMEM_H */
|
||||
#endif /* !__ANDROID__ */
|
||||
|
||||
|
@ -30,24 +30,25 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define CMPLOG_LVL_MAX 3
|
||||
|
||||
#define CMP_MAP_W 65536
|
||||
#define CMP_MAP_H 256
|
||||
#define CMP_MAP_H 32
|
||||
#define CMP_MAP_RTN_H (CMP_MAP_H / 4)
|
||||
|
||||
#define SHAPE_BYTES(x) (x + 1)
|
||||
|
||||
#define CMP_TYPE_INS 0
|
||||
#define CMP_TYPE_RTN 1
|
||||
#define CMP_TYPE_INS 1
|
||||
#define CMP_TYPE_RTN 2
|
||||
|
||||
struct cmp_header {
|
||||
|
||||
unsigned hits : 20;
|
||||
|
||||
unsigned cnt : 20;
|
||||
unsigned id : 16;
|
||||
|
||||
unsigned shape : 5; // from 0 to 31
|
||||
unsigned type : 1;
|
||||
unsigned hits : 24;
|
||||
unsigned id : 24;
|
||||
unsigned shape : 5;
|
||||
unsigned type : 2;
|
||||
unsigned attribute : 4;
|
||||
unsigned reserved : 5;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
@ -55,6 +56,8 @@ struct cmp_operands {
|
||||
|
||||
u64 v0;
|
||||
u64 v1;
|
||||
u64 v0_128;
|
||||
u64 v1_128;
|
||||
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define STRINGIFY_VAL_SIZE_MAX (16)
|
||||
|
||||
void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
|
||||
void print_suggested_envs(char *mispelled_env);
|
||||
void check_environment_vars(char **env);
|
||||
|
||||
char **argv_cpy_dup(int argc, char **argv);
|
||||
@ -47,6 +48,7 @@ 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);
|
||||
u8 * get_libqasan_path(u8 *own_loc);
|
||||
|
||||
extern u8 be_quiet;
|
||||
extern u8 *doc_path; /* path to documentation dir */
|
||||
@ -56,6 +58,11 @@ extern u8 *doc_path; /* path to documentation dir */
|
||||
|
||||
u8 *find_binary(u8 *fname);
|
||||
|
||||
/* Parses the kill signal environment variable, FATALs on error.
|
||||
If the env is not set, sets the env to default_signal for the signal handlers
|
||||
and returns the default_signal. */
|
||||
int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal);
|
||||
|
||||
/* Read a bitmap from file fname to memory
|
||||
This is for the -B option again. */
|
||||
|
||||
|
109
include/config.h
109
include/config.h
@ -10,7 +10,7 @@
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
Copyright 2019-2021 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.
|
||||
@ -23,12 +23,10 @@
|
||||
#ifndef _HAVE_CONFIG_H
|
||||
#define _HAVE_CONFIG_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++3.00c"
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++3.10c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -36,11 +34,55 @@
|
||||
* *
|
||||
******************************************************/
|
||||
|
||||
/* CMPLOG/REDQUEEN TUNING
|
||||
*
|
||||
* Here you can modify tuning and solving options for CMPLOG.
|
||||
* Note that these are run-time options for afl-fuzz, no target
|
||||
* recompilation required.
|
||||
*
|
||||
*/
|
||||
|
||||
/* if TRANSFORM is enabled with '-l T', this additionally enables base64
|
||||
encoding/decoding */
|
||||
// #define CMPLOG_SOLVE_TRANSFORM_BASE64
|
||||
|
||||
/* If a redqueen pass finds more than one solution, try to combine them? */
|
||||
#define CMPLOG_COMBINE
|
||||
|
||||
/* Minimum % of the corpus to perform cmplog on. Default: 10% */
|
||||
#define CMPLOG_CORPUS_PERCENT 5U
|
||||
|
||||
/* Number of potential positions from which we decide if cmplog becomes
|
||||
useless, default 8096 */
|
||||
#define CMPLOG_POSITIONS_MAX 8096U
|
||||
|
||||
/* Maximum allowed fails per CMP value. Default: 128 */
|
||||
#define CMPLOG_FAIL_MAX 128
|
||||
|
||||
/* Now non-cmplog configuration options */
|
||||
|
||||
/* console output colors: There are three ways to configure its behavior
|
||||
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
||||
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
|
||||
* 2. defined USE_COLOR && !defined ALWAYS_COLORED
|
||||
* -> depending on env var AFL_NO_COLOR=1 colors can be switched off
|
||||
* at run-time. Default is to use colors.
|
||||
* 3. colored outputs fixed off: !defined USE_COLOR
|
||||
* The env var. AFL_NO_COLOR will have no effect
|
||||
*/
|
||||
|
||||
/* Comment out to disable terminal colors (note that this makes afl-analyze
|
||||
a lot less nice): */
|
||||
|
||||
#define USE_COLOR
|
||||
|
||||
#ifdef USE_COLOR
|
||||
/* Comment in to always enable terminal colors */
|
||||
/* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR
|
||||
*/
|
||||
#define ALWAYS_COLORED 1
|
||||
#endif
|
||||
|
||||
/* StatsD config
|
||||
Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
|
||||
variable.
|
||||
@ -52,7 +94,7 @@
|
||||
/* 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
|
||||
// #define _WANT_ORIGINAL_AFL_ALLOC
|
||||
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
@ -63,11 +105,11 @@
|
||||
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||
also used for detecting hangs; the actual value is auto-scaled: */
|
||||
|
||||
#define EXEC_TIMEOUT 1000
|
||||
#define EXEC_TIMEOUT 1000U
|
||||
|
||||
/* Timeout rounding factor when auto-scaling (milliseconds): */
|
||||
|
||||
#define EXEC_TM_ROUND 20
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||
@ -76,48 +118,48 @@
|
||||
|
||||
/* Default memory limit for child process (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT 0
|
||||
#define MEM_LIMIT 0U
|
||||
|
||||
/* Default memory limit when running in QEMU mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_QEMU 0
|
||||
#define MEM_LIMIT_QEMU 0U
|
||||
|
||||
/* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_UNICORN 0
|
||||
#define MEM_LIMIT_UNICORN 0U
|
||||
|
||||
/* Number of calibration cycles per every new test case (and for test
|
||||
cases that show variable behavior): */
|
||||
|
||||
#define CAL_CYCLES 8
|
||||
#define CAL_CYCLES_LONG 40
|
||||
#define CAL_CYCLES 8U
|
||||
#define CAL_CYCLES_LONG 40U
|
||||
|
||||
/* Number of subsequent timeouts before abandoning an input file: */
|
||||
|
||||
#define TMOUT_LIMIT 250
|
||||
#define TMOUT_LIMIT 250U
|
||||
|
||||
/* Maximum number of unique hangs or crashes to record: */
|
||||
|
||||
#define KEEP_UNIQUE_HANG 500
|
||||
#define KEEP_UNIQUE_CRASH 5000
|
||||
#define KEEP_UNIQUE_HANG 500U
|
||||
#define KEEP_UNIQUE_CRASH 5000U
|
||||
|
||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||
|
||||
#define HAVOC_CYCLES 256
|
||||
#define HAVOC_CYCLES_INIT 1024
|
||||
#define HAVOC_CYCLES 256U
|
||||
#define HAVOC_CYCLES_INIT 1024U
|
||||
|
||||
/* Maximum multiplier for the above (should be a power of two, beware
|
||||
of 32-bit int overflows): */
|
||||
|
||||
#define HAVOC_MAX_MULT 64
|
||||
#define HAVOC_MAX_MULT_MOPT 64
|
||||
#define HAVOC_MAX_MULT 64U
|
||||
#define HAVOC_MAX_MULT_MOPT 64U
|
||||
|
||||
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
||||
|
||||
#define HAVOC_MIN 12
|
||||
#define HAVOC_MIN 12U
|
||||
|
||||
/* Power Schedule Divisor */
|
||||
#define POWER_BETA 1
|
||||
#define POWER_BETA 1U
|
||||
#define MAX_FACTOR (POWER_BETA * 32)
|
||||
|
||||
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
|
||||
@ -129,19 +171,19 @@
|
||||
In other words, the default (n = 4) produces 2, 4, 8, 16
|
||||
stacked tweaks: */
|
||||
|
||||
#define HAVOC_STACK_POW2 4
|
||||
#define HAVOC_STACK_POW2 4U
|
||||
|
||||
/* Caps on block sizes for cloning and deletion operations. Each of these
|
||||
ranges has a 33% probability of getting picked, except for the first
|
||||
two cycles where smaller blocks are favored: */
|
||||
|
||||
#define HAVOC_BLK_SMALL 32
|
||||
#define HAVOC_BLK_MEDIUM 128
|
||||
#define HAVOC_BLK_LARGE 1500
|
||||
#define HAVOC_BLK_SMALL 32U
|
||||
#define HAVOC_BLK_MEDIUM 128U
|
||||
#define HAVOC_BLK_LARGE 1500U
|
||||
|
||||
/* Extra-large blocks, selected very rarely (<5% of the time): */
|
||||
|
||||
#define HAVOC_BLK_XL 32768
|
||||
#define HAVOC_BLK_XL 32768U
|
||||
|
||||
/* Probabilities of skipping non-favored entries in the queue, expressed as
|
||||
percentages: */
|
||||
@ -169,9 +211,11 @@
|
||||
#define TRIM_START_STEPS 16
|
||||
#define TRIM_END_STEPS 1024
|
||||
|
||||
/* Maximum size of input file, in bytes (keep under 100MB): */
|
||||
/* Maximum size of input file, in bytes (keep under 100MB, default 1MB):
|
||||
(note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c
|
||||
and afl-fuzz-state.c have to be changed as well! */
|
||||
|
||||
#define MAX_FILE (1 * 1024 * 1024)
|
||||
#define MAX_FILE (1 * 1024 * 1024U)
|
||||
|
||||
/* The same, for the test case minimizer: */
|
||||
|
||||
@ -236,6 +280,11 @@
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
|
||||
/* Sync time (minimum time between syncing in ms, time is halfed for -M main
|
||||
nodes) - default is 30 minutes: */
|
||||
|
||||
#define SYNC_TIME (30 * 60 * 1000)
|
||||
|
||||
/* Output directory reuse grace period (minutes): */
|
||||
|
||||
#define OUTPUT_GRACE 25
|
||||
@ -363,7 +412,7 @@
|
||||
after changing this - otherwise, SEGVs may ensue. */
|
||||
|
||||
#define MAP_SIZE_POW2 16
|
||||
#define MAP_SIZE (1 << MAP_SIZE_POW2)
|
||||
#define MAP_SIZE (1U << MAP_SIZE_POW2)
|
||||
|
||||
/* Maximum allocator request size (keep well under INT_MAX): */
|
||||
|
||||
|
112
include/coverage-32.h
Normal file
112
include/coverage-32.h
Normal file
@ -0,0 +1,112 @@
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end);
|
||||
u32 classify_word(u32 word);
|
||||
|
||||
inline u32 classify_word(u32 word) {
|
||||
|
||||
u16 mem16[2];
|
||||
memcpy(mem16, &word, sizeof(mem16));
|
||||
|
||||
mem16[0] = count_class_lookup16[mem16[0]];
|
||||
mem16[1] = count_class_lookup16[mem16[1]];
|
||||
|
||||
memcpy(&word, mem16, sizeof(mem16));
|
||||
return word;
|
||||
|
||||
}
|
||||
|
||||
void simplify_trace(afl_state_t *afl, u8 *bytes) {
|
||||
|
||||
u32 *mem = (u32 *)bytes;
|
||||
u32 i = (afl->fsrv.map_size >> 2);
|
||||
|
||||
while (i--) {
|
||||
|
||||
/* Optimize for sparse bitmaps. */
|
||||
|
||||
if (unlikely(*mem)) {
|
||||
|
||||
u8 *mem8 = (u8 *)mem;
|
||||
|
||||
mem8[0] = simplify_lookup[mem8[0]];
|
||||
mem8[1] = simplify_lookup[mem8[1]];
|
||||
mem8[2] = simplify_lookup[mem8[2]];
|
||||
mem8[3] = simplify_lookup[mem8[3]];
|
||||
|
||||
} else
|
||||
|
||||
*mem = 0x01010101;
|
||||
|
||||
mem++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void classify_counts(afl_forkserver_t *fsrv) {
|
||||
|
||||
u32 *mem = (u32 *)fsrv->trace_bits;
|
||||
u32 i = (fsrv->map_size >> 2);
|
||||
|
||||
while (i--) {
|
||||
|
||||
/* Optimize for sparse bitmaps. */
|
||||
|
||||
if (unlikely(*mem)) { *mem = classify_word(*mem); }
|
||||
|
||||
mem++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Updates the virgin bits, then reflects whether a new count or a new tuple is
|
||||
* seen in ret. */
|
||||
inline void discover_word(u8 *ret, u32 *current, u32 *virgin) {
|
||||
|
||||
/* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
|
||||
that have not been already cleared from the virgin map - since this will
|
||||
almost always be the case. */
|
||||
|
||||
if (*current & *virgin) {
|
||||
|
||||
if (likely(*ret < 2)) {
|
||||
|
||||
u8 *cur = (u8 *)current;
|
||||
u8 *vir = (u8 *)virgin;
|
||||
|
||||
/* Looks like we have not found any new bytes yet; see if any non-zero
|
||||
bytes in current[] are pristine in virgin[]. */
|
||||
|
||||
if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
|
||||
(cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff))
|
||||
*ret = 2;
|
||||
else
|
||||
*ret = 1;
|
||||
|
||||
}
|
||||
|
||||
*virgin &= ~*current;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define PACK_SIZE 16
|
||||
inline u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end) {
|
||||
|
||||
for (; current < current_end; virgin += 4, current += 4) {
|
||||
|
||||
if (current[0] && classify_word(current[0]) & virgin[0]) return 1;
|
||||
if (current[1] && classify_word(current[1]) & virgin[1]) return 1;
|
||||
if (current[2] && classify_word(current[2]) & virgin[2]) return 1;
|
||||
if (current[3] && classify_word(current[3]) & virgin[3]) return 1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
189
include/coverage-64.h
Normal file
189
include/coverage-64.h
Normal file
@ -0,0 +1,189 @@
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
#if (defined(__AVX512F__) && defined(__AVX512DQ__)) || defined(__AVX2__)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end);
|
||||
u64 classify_word(u64 word);
|
||||
|
||||
inline u64 classify_word(u64 word) {
|
||||
|
||||
u16 mem16[4];
|
||||
memcpy(mem16, &word, sizeof(mem16));
|
||||
|
||||
mem16[0] = count_class_lookup16[mem16[0]];
|
||||
mem16[1] = count_class_lookup16[mem16[1]];
|
||||
mem16[2] = count_class_lookup16[mem16[2]];
|
||||
mem16[3] = count_class_lookup16[mem16[3]];
|
||||
|
||||
memcpy(&word, mem16, sizeof(mem16));
|
||||
return word;
|
||||
|
||||
}
|
||||
|
||||
void simplify_trace(afl_state_t *afl, u8 *bytes) {
|
||||
|
||||
u64 *mem = (u64 *)bytes;
|
||||
u32 i = (afl->fsrv.map_size >> 3);
|
||||
|
||||
while (i--) {
|
||||
|
||||
/* Optimize for sparse bitmaps. */
|
||||
|
||||
if (unlikely(*mem)) {
|
||||
|
||||
u8 *mem8 = (u8 *)mem;
|
||||
|
||||
mem8[0] = simplify_lookup[mem8[0]];
|
||||
mem8[1] = simplify_lookup[mem8[1]];
|
||||
mem8[2] = simplify_lookup[mem8[2]];
|
||||
mem8[3] = simplify_lookup[mem8[3]];
|
||||
mem8[4] = simplify_lookup[mem8[4]];
|
||||
mem8[5] = simplify_lookup[mem8[5]];
|
||||
mem8[6] = simplify_lookup[mem8[6]];
|
||||
mem8[7] = simplify_lookup[mem8[7]];
|
||||
|
||||
} else
|
||||
|
||||
*mem = 0x0101010101010101ULL;
|
||||
|
||||
mem++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void classify_counts(afl_forkserver_t *fsrv) {
|
||||
|
||||
u64 *mem = (u64 *)fsrv->trace_bits;
|
||||
u32 i = (fsrv->map_size >> 3);
|
||||
|
||||
while (i--) {
|
||||
|
||||
/* Optimize for sparse bitmaps. */
|
||||
|
||||
if (unlikely(*mem)) { *mem = classify_word(*mem); }
|
||||
|
||||
mem++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Updates the virgin bits, then reflects whether a new count or a new tuple is
|
||||
* seen in ret. */
|
||||
inline void discover_word(u8 *ret, u64 *current, u64 *virgin) {
|
||||
|
||||
/* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
|
||||
that have not been already cleared from the virgin map - since this will
|
||||
almost always be the case. */
|
||||
|
||||
if (*current & *virgin) {
|
||||
|
||||
if (likely(*ret < 2)) {
|
||||
|
||||
u8 *cur = (u8 *)current;
|
||||
u8 *vir = (u8 *)virgin;
|
||||
|
||||
/* Looks like we have not found any new bytes yet; see if any non-zero
|
||||
bytes in current[] are pristine in virgin[]. */
|
||||
|
||||
if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
|
||||
(cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
|
||||
(cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
|
||||
(cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
|
||||
*ret = 2;
|
||||
else
|
||||
*ret = 1;
|
||||
|
||||
}
|
||||
|
||||
*virgin &= ~*current;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(__AVX512F__) && defined(__AVX512DQ__)
|
||||
#define PACK_SIZE 64
|
||||
inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
|
||||
|
||||
for (; current != current_end; virgin += 8, current += 8) {
|
||||
|
||||
__m512i value = *(__m512i *)current;
|
||||
__mmask8 mask = _mm512_testn_epi64_mask(value, value);
|
||||
|
||||
/* All bytes are zero. */
|
||||
if (mask == 0xff) continue;
|
||||
|
||||
/* Look for nonzero bytes and check for new bits. */
|
||||
#define UNROLL(x) \
|
||||
if (!(mask & (1 << x)) && classify_word(current[x]) & virgin[x]) return 1
|
||||
UNROLL(0);
|
||||
UNROLL(1);
|
||||
UNROLL(2);
|
||||
UNROLL(3);
|
||||
UNROLL(4);
|
||||
UNROLL(5);
|
||||
UNROLL(6);
|
||||
UNROLL(7);
|
||||
#undef UNROLL
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(PACK_SIZE) && defined(__AVX2__)
|
||||
#define PACK_SIZE 32
|
||||
inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
|
||||
|
||||
__m256i zeroes = _mm256_setzero_si256();
|
||||
|
||||
for (; current < current_end; virgin += 4, current += 4) {
|
||||
|
||||
__m256i value = *(__m256i *)current;
|
||||
__m256i cmp = _mm256_cmpeq_epi64(value, zeroes);
|
||||
u32 mask = _mm256_movemask_epi8(cmp);
|
||||
|
||||
/* All bytes are zero. */
|
||||
if (mask == (u32)-1) continue;
|
||||
|
||||
/* Look for nonzero bytes and check for new bits. */
|
||||
if (!(mask & 0xff) && classify_word(current[0]) & virgin[0]) return 1;
|
||||
if (!(mask & 0xff00) && classify_word(current[1]) & virgin[1]) return 1;
|
||||
if (!(mask & 0xff0000) && classify_word(current[2]) & virgin[2]) return 1;
|
||||
if (!(mask & 0xff000000) && classify_word(current[3]) & virgin[3]) return 1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(PACK_SIZE)
|
||||
#define PACK_SIZE 32
|
||||
inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
|
||||
|
||||
for (; current < current_end; virgin += 4, current += 4) {
|
||||
|
||||
if (current[0] && classify_word(current[0]) & virgin[0]) return 1;
|
||||
if (current[1] && classify_word(current[1]) & virgin[1]) return 1;
|
||||
if (current[2] && classify_word(current[2]) & virgin[2]) return 1;
|
||||
if (current[3] && classify_word(current[3]) & virgin[3]) return 1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -168,12 +168,84 @@
|
||||
* Debug & error macros *
|
||||
************************/
|
||||
|
||||
/* Just print stuff to the appropriate stream. */
|
||||
#if defined USE_COLOR && !defined ALWAYS_COLORED
|
||||
#include <unistd.h>
|
||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||
static inline const char *colorfilter(const char *x) {
|
||||
|
||||
static int once = 1;
|
||||
static int disabled = 0;
|
||||
|
||||
if (once) {
|
||||
|
||||
/* when there is no tty -> we always want filtering
|
||||
* when AFL_NO_UI is set filtering depends on AFL_NO_COLOR
|
||||
* otherwise we want always colors
|
||||
*/
|
||||
disabled =
|
||||
isatty(2) && (!getenv("AFL_NO_UI") ||
|
||||
(!getenv("AFL_NO_COLOR") && !getenv("AFL_NO_COLOUR")));
|
||||
once = 0;
|
||||
|
||||
}
|
||||
|
||||
if (likely(disabled)) return x;
|
||||
|
||||
static char monochromestring[4096];
|
||||
char * d = monochromestring;
|
||||
int in_seq = 0;
|
||||
|
||||
while (*x) {
|
||||
|
||||
if (in_seq && *x == 'm') {
|
||||
|
||||
in_seq = 0;
|
||||
|
||||
} else {
|
||||
|
||||
if (!in_seq && *x == '\x1b') { in_seq = 1; }
|
||||
if (!in_seq) { *d++ = *x; }
|
||||
|
||||
}
|
||||
|
||||
++x;
|
||||
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return monochromestring;
|
||||
|
||||
}
|
||||
|
||||
#ifdef MESSAGES_TO_STDOUT
|
||||
#define SAYF(x...) printf(x)
|
||||
#else
|
||||
#define SAYF(x...) fprintf(stderr, x)
|
||||
#define colorfilter(x) x /* no filtering necessary */
|
||||
#endif
|
||||
|
||||
/* macro magic to transform the first parameter to SAYF
|
||||
* through colorfilter which strips coloring */
|
||||
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
|
||||
_15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, \
|
||||
_27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, \
|
||||
_39, _40, NAME, ...) \
|
||||
NAME
|
||||
|
||||
#define SAYF(...) \
|
||||
GET_MACRO(__VA_ARGS__, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
|
||||
SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
|
||||
SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
|
||||
SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
|
||||
SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \
|
||||
SAYF_N, SAYF_1) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
#define SAYF_1(x) MY_SAYF(colorfilter(x))
|
||||
#define SAYF_N(x, ...) MY_SAYF(colorfilter(x), __VA_ARGS__)
|
||||
|
||||
/* Just print stuff to the appropriate stream. */
|
||||
#ifdef MESSAGES_TO_STDOUT
|
||||
#define MY_SAYF(x...) printf(x)
|
||||
#else
|
||||
#define MY_SAYF(x...) fprintf(stderr, x)
|
||||
#endif /* ^MESSAGES_TO_STDOUT */
|
||||
|
||||
/* Show a prefixed warning. */
|
||||
@ -224,7 +296,7 @@
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
__FILE__, (u32)__LINE__); \
|
||||
exit(1); \
|
||||
\
|
||||
} while (0)
|
||||
@ -237,7 +309,7 @@
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
__FILE__, (u32)__LINE__); \
|
||||
abort(); \
|
||||
\
|
||||
} while (0)
|
||||
@ -251,7 +323,7 @@
|
||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||
"\n[-] SYSTEM ERROR : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \
|
||||
__FILE__, __LINE__); \
|
||||
__FILE__, (u32)__LINE__); \
|
||||
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
|
||||
exit(1); \
|
||||
\
|
||||
@ -272,12 +344,12 @@
|
||||
|
||||
/* Show a prefixed debug output. */
|
||||
|
||||
#define DEBUGF(x...) \
|
||||
do { \
|
||||
\
|
||||
SAYF(cMGN "[D] " cBRI "DEBUG: " cRST x); \
|
||||
SAYF(cRST ""); \
|
||||
\
|
||||
#define DEBUGF(x...) \
|
||||
do { \
|
||||
\
|
||||
fprintf(stderr, cMGN "[D] " cBRI "DEBUG: " cRST x); \
|
||||
fprintf(stderr, cRST ""); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Error-checking versions of read() and write() that call RPFATAL() as
|
||||
|
@ -28,6 +28,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CC",
|
||||
"AFL_CMIN_ALLOW_ANY",
|
||||
"AFL_CMIN_CRASHES_ONLY",
|
||||
"AFL_CMPLOG_ONLY_NEW",
|
||||
"AFL_CODE_END",
|
||||
"AFL_CODE_START",
|
||||
"AFL_COMPCOV_BINNAME",
|
||||
@ -42,11 +43,13 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_DEBUG_GDB",
|
||||
"AFL_DISABLE_TRIM",
|
||||
"AFL_DONT_OPTIMIZE",
|
||||
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||
"AFL_DUMB_FORKSRV",
|
||||
"AFL_ENTRYPOINT",
|
||||
"AFL_EXIT_WHEN_DONE",
|
||||
"AFL_FAST_CAL",
|
||||
"AFL_FORCE_UI",
|
||||
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||
"AFL_GCC_ALLOWLIST",
|
||||
"AFL_GCC_DENYLIST",
|
||||
"AFL_GCC_BLOCKLIST",
|
||||
@ -58,9 +61,11 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FORKSRV_INIT_TMOUT",
|
||||
"AFL_HARDEN",
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
||||
"AFL_IGNORE_UNKNOWN_ENVS",
|
||||
"AFL_IMPORT_FIRST",
|
||||
"AFL_INST_LIBS",
|
||||
"AFL_INST_RATIO",
|
||||
"AFL_KILL_SIGNAL",
|
||||
"AFL_KEEP_TRACES",
|
||||
"AFL_KEEP_ASSEMBLY",
|
||||
"AFL_LD_HARD_FAIL",
|
||||
@ -78,8 +83,8 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_LLVM_CTX",
|
||||
"AFL_LLVM_DICT2FILE",
|
||||
"AFL_LLVM_DOCUMENT_IDS",
|
||||
"AFL_LLVM_INSTRUMENT",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
"AFL_LLVM_INSTRUMENT",
|
||||
"AFL_LLVM_LTO_AUTODICTIONARY",
|
||||
"AFL_LLVM_AUTODICTIONARY",
|
||||
"AFL_LLVM_SKIPSINGLEBLOCK",
|
||||
@ -103,6 +108,10 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_NO_ARITH",
|
||||
"AFL_NO_AUTODICT",
|
||||
"AFL_NO_BUILTIN",
|
||||
#if defined USE_COLOR && !defined ALWAYS_COLORED
|
||||
"AFL_NO_COLOR",
|
||||
"AFL_NO_COLOUR",
|
||||
#endif
|
||||
"AFL_NO_CPU_RED",
|
||||
"AFL_NO_FORKSRV",
|
||||
"AFL_NO_UI",
|
||||
@ -122,6 +131,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_QEMU_DEBUG_MAPS",
|
||||
"AFL_QEMU_DISABLE_CACHE",
|
||||
"AFL_QEMU_DRIVER_NO_HOOK",
|
||||
"AFL_QEMU_FORCE_DFL",
|
||||
"AFL_QEMU_PERSISTENT_ADDR",
|
||||
"AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR",
|
||||
@ -157,6 +167,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_WINE_PATH",
|
||||
"AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW",
|
||||
"AFL_USE_QASAN",
|
||||
NULL
|
||||
|
||||
};
|
||||
|
@ -64,7 +64,7 @@ typedef struct afl_forkserver {
|
||||
|
||||
FILE *plot_file; /* Gnuplot output file */
|
||||
|
||||
/* Note: lat_run_timed_out is u32 to send it to the child as 4 byte array */
|
||||
/* Note: last_run_timed_out is u32 to send it to the child as 4 byte array */
|
||||
u32 last_run_timed_out; /* Traced process timed out? */
|
||||
|
||||
u8 last_kill_signal; /* Signal that killed the child */
|
||||
@ -83,6 +83,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
bool uses_asan; /* Target uses ASAN? */
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
||||
u8 crash_exitcode; /* The crash exitcode specified */
|
||||
|
||||
@ -99,6 +101,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len);
|
||||
|
||||
u8 kill_signal;
|
||||
|
||||
} afl_forkserver_t;
|
||||
|
||||
typedef enum fsrv_run_result {
|
||||
@ -116,11 +120,14 @@ void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len);
|
||||
fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
|
||||
volatile u8 *stop_soon_p);
|
||||
void afl_fsrv_killall(void);
|
||||
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_kill(afl_forkserver_t *fsrv);
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define MSG_FORK_ON_APPLE \
|
||||
|
@ -51,6 +51,7 @@ typedef struct sharedmem {
|
||||
size_t map_size; /* actual allocated size */
|
||||
|
||||
int cmplog_mode;
|
||||
int shmemfuzz_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
} sharedmem_t;
|
||||
|
@ -25,10 +25,15 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef uint128_t u128;
|
||||
#endif
|
||||
|
||||
/* Extended forkserver option values */
|
||||
|
||||
@ -50,7 +55,7 @@ typedef uint32_t u32;
|
||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
|
||||
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
|
||||
#define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1)
|
||||
#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
|
||||
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
|
||||
#define FS_OPT_SET_MAPSIZE(x) \
|
||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||
@ -61,6 +66,10 @@ typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef __int128 int128_t;
|
||||
typedef int128_t s128;
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) \
|
||||
@ -114,6 +123,33 @@ typedef int64_t s64;
|
||||
\
|
||||
})
|
||||
|
||||
// It is impossible to define 128 bit constants, so ...
|
||||
#ifdef WORD_SIZE_64
|
||||
#define SWAPN(_x, _l) \
|
||||
({ \
|
||||
\
|
||||
u128 _res = (_x), _ret; \
|
||||
char *d = (char *)&_ret, *s = (char *)&_res; \
|
||||
int i; \
|
||||
for (i = 0; i < 16; i++) \
|
||||
d[15 - i] = s[i]; \
|
||||
u32 sr = 128U - ((_l) << 3U); \
|
||||
(_ret >>= sr); \
|
||||
(u128) _ret; \
|
||||
\
|
||||
})
|
||||
#endif
|
||||
|
||||
#define SWAPNN(_x, _y, _l) \
|
||||
({ \
|
||||
\
|
||||
char *d = (char *)(_x), *s = (char *)(_y); \
|
||||
u32 i, l = (_l)-1; \
|
||||
for (i = 0; i <= l; i++) \
|
||||
d[l - i] = s[i]; \
|
||||
\
|
||||
})
|
||||
|
||||
#ifdef AFL_LLVM_PASS
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define AFL_SR(s) (srandom(s))
|
||||
|
@ -200,7 +200,7 @@ struct InsTrim : public ModulePass {
|
||||
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
|
||||
|
||||
if (ctx_str)
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||
#else
|
||||
@ -211,7 +211,7 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||
@ -224,7 +224,7 @@ struct InsTrim : public ModulePass {
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||
#else
|
||||
@ -407,10 +407,10 @@ struct InsTrim : public ModulePass {
|
||||
// does the function have calls? and is any of the calls larger than
|
||||
// one basic block?
|
||||
has_calls = 0;
|
||||
for (auto &BB : F) {
|
||||
for (auto &BB2 : F) {
|
||||
|
||||
if (has_calls) break;
|
||||
for (auto &IN : BB) {
|
||||
for (auto &IN : BB2) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -454,12 +454,12 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
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) {
|
||||
for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
|
||||
|
||||
BasicBlock *PBB = *PI;
|
||||
auto It = PredMap.insert({PBB, genLabel()});
|
||||
unsigned Label = It.first->second;
|
||||
cur_loc = Label;
|
||||
// cur_loc = Label;
|
||||
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
|
||||
|
||||
}
|
||||
@ -568,7 +568,7 @@ struct InsTrim : public ModulePass {
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
|
||||
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr,
|
||||
OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr,
|
||||
total_rs, total_hs, modeline);
|
||||
|
||||
}
|
||||
|
2
instrumentation/Makefile
Normal file
2
instrumentation/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
all:
|
||||
@echo "no need to do make in the instrumentation/ directory :) - it is all done in the main one"
|
@ -332,11 +332,11 @@ bool Indistinguish(uint32_t node1, uint32_t node2) {
|
||||
|
||||
void MakeUniq(uint32_t now) {
|
||||
|
||||
bool StopFlag = false;
|
||||
if (Marked.find(now) == Marked.end()) {
|
||||
|
||||
for (uint32_t pred1 : t_Pred[now]) {
|
||||
|
||||
bool StopFlag = false;
|
||||
for (uint32_t pred2 : t_Pred[now]) {
|
||||
|
||||
if (pred1 == pred2) continue;
|
||||
|
@ -1,8 +1,9 @@
|
||||
# Using afl++ with partial instrumentation
|
||||
|
||||
This file describes how to selectively instrument only source files
|
||||
or functions that are of interest to you using the LLVM and GCC_PLUGIN
|
||||
instrumentation provided by afl++.
|
||||
This file describes two different mechanisms to selectively instrument
|
||||
only specific parts in the target.
|
||||
|
||||
Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc.
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
@ -12,28 +13,49 @@ the program, leaving the rest uninstrumented. This helps to focus the fuzzer
|
||||
on the important parts of the program, avoiding undesired noise and
|
||||
disturbance by uninteresting code being exercised.
|
||||
|
||||
For this purpose, a "partial instrumentation" support en par with llvm sancov
|
||||
is provided by afl++ that allows to specify on a source file and function
|
||||
level which function should be compiled with or without instrumentation.
|
||||
For this purpose, "partial instrumentation" support is provided by afl++ that
|
||||
allows to specify what should be instrumented and what not.
|
||||
|
||||
Note: When using PCGUARD mode - and llvm 12+ - you can use this instead:
|
||||
https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
|
||||
Both mechanisms can be used together.
|
||||
|
||||
The llvm sancov list format is fully supported by afl++, however afl++ has
|
||||
more flexibility.
|
||||
## 2) Selective instrumentation with __AFL_COVERAGE_... directives
|
||||
|
||||
## 2a) Building the LLVM module
|
||||
In this mechanism the selective instrumentation is done in the source code.
|
||||
|
||||
The new code is part of the existing afl++ LLVM module in the instrumentation/
|
||||
subdirectory. There is nothing specifically to do for the build :)
|
||||
After the includes a special define has to be made, eg.:
|
||||
|
||||
## 2b) Building the GCC module
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
// ...
|
||||
|
||||
__AFL_COVERAGE(); // <- required for this feature to work
|
||||
```
|
||||
|
||||
The new code is part of the existing afl++ GCC_PLUGIN module in the
|
||||
instrumentation/ subdirectory. There is nothing specifically to do for
|
||||
the build :)
|
||||
If you want to disable the coverage at startup until you specify coverage
|
||||
should be started, then add `__AFL_COVERAGE_START_OFF();` at that position.
|
||||
|
||||
## 3) How to use the partial instrumentation mode
|
||||
From here on out you have the following macros available that you can use
|
||||
in any function where you want:
|
||||
|
||||
* `__AFL_COVERAGE_ON();` - enable coverage from this point onwards
|
||||
* `__AFL_COVERAGE_OFF();` - disable coverage from this point onwards
|
||||
* `__AFL_COVERAGE_DISCARD();` - reset all coverage gathered until this point
|
||||
* `__AFL_COVERAGE_SKIP();` - mark this test case as unimportant. Whatever happens, afl-fuzz will ignore it.
|
||||
|
||||
A special function is `__afl_coverage_interesting`.
|
||||
To use this, you must define `void __afl_coverage_interesting(u8 val, u32 id);`.
|
||||
Then you can use this function globally, where the `val` parameter can be set
|
||||
by you, the `id` parameter is for afl-fuzz and will be overwritten.
|
||||
Note that useful parameters for `val` are: 1, 2, 3, 4, 8, 16, 32, 64, 128.
|
||||
A value of e.g. 33 will be seen as 32 for coverage purposes.
|
||||
|
||||
## 3) Selective instrumentation with AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST
|
||||
|
||||
This feature is equivalent to llvm 12 sancov feature and allows to specify
|
||||
on a filename and/or function name level to instrument these or skip them.
|
||||
|
||||
### 3a) How to use the partial instrumentation mode
|
||||
|
||||
In order to build with partial instrumentation, you need to build with
|
||||
afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++.
|
||||
@ -90,7 +112,7 @@ fun: MallocFoo
|
||||
```
|
||||
Note that whitespace is ignored and comments (`# foo`) are supported.
|
||||
|
||||
## 4) UNIX-style pattern matching
|
||||
### 3b) UNIX-style pattern matching
|
||||
|
||||
You can add UNIX-style pattern matching in the "instrument file list" entries.
|
||||
See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
|
||||
|
@ -168,26 +168,7 @@ This is the most powerful and effective fuzzing you can do.
|
||||
Please see [README.persistent_mode.md](README.persistent_mode.md) for a
|
||||
full explanation.
|
||||
|
||||
## 7) Bonus feature: 'trace-pc-guard' mode
|
||||
|
||||
LLVM is shipping with a built-in execution tracing feature
|
||||
that provides AFL with the necessary tracing data without the need to
|
||||
post-process the assembly or install any compiler plugins. See:
|
||||
|
||||
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
|
||||
|
||||
If you have not an outdated compiler and want to give it a try, build
|
||||
targets this way:
|
||||
|
||||
```
|
||||
AFL_LLVM_INSTRUMENT=PCGUARD make
|
||||
```
|
||||
|
||||
Note that this is currently the default if you use LLVM >= 7, as it is the best
|
||||
mode. Recommended is LLVM >= 9.
|
||||
If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode.
|
||||
|
||||
## 8) Bonus feature: 'dict2file' pass
|
||||
## 7) Bonus feature: 'dict2file' pass
|
||||
|
||||
Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation
|
||||
all constant string compare parameters will be written to this file to be
|
||||
|
@ -88,16 +88,35 @@ apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
### Building llvm yourself (version 12)
|
||||
|
||||
Building llvm from github takes quite some long time and is not painless:
|
||||
```
|
||||
```sh
|
||||
sudo apt install binutils-dev # this is *essential*!
|
||||
git clone https://github.com/llvm/llvm-project
|
||||
git clone --depth=1 https://github.com/llvm/llvm-project
|
||||
cd llvm-project
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/
|
||||
make -j $(nproc)
|
||||
export PATH=`pwd`/bin:$PATH
|
||||
export LLVM_CONFIG=`pwd`/bin/llvm-config
|
||||
|
||||
# Add -G Ninja if ninja-build installed
|
||||
# "Building with ninja significantly improves your build time, especially with
|
||||
# incremental builds, and improves your memory usage."
|
||||
cmake \
|
||||
-DCLANG_INCLUDE_DOCS="OFF" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLVM_BINUTILS_INCDIR=/usr/include/ \
|
||||
-DLLVM_BUILD_LLVM_DYLIB="ON" \
|
||||
-DLLVM_ENABLE_BINDINGS="OFF" \
|
||||
-DLLVM_ENABLE_PROJECTS='clang;compiler-rt;libcxx;libcxxabi;libunwind;lld' \
|
||||
-DLLVM_ENABLE_WARNINGS="OFF" \
|
||||
-DLLVM_INCLUDE_BENCHMARKS="OFF" \
|
||||
-DLLVM_INCLUDE_DOCS="OFF" \
|
||||
-DLLVM_INCLUDE_EXAMPLES="OFF" \
|
||||
-DLLVM_INCLUDE_TESTS="OFF" \
|
||||
-DLLVM_LINK_LLVM_DYLIB="ON" \
|
||||
-DLLVM_TARGETS_TO_BUILD="host" \
|
||||
../llvm/
|
||||
cmake --build . --parallel
|
||||
export PATH="$(pwd)/bin:$PATH"
|
||||
export LLVM_CONFIG="$(pwd)/bin/llvm-config"
|
||||
export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
cd /path/to/AFLplusplus/
|
||||
make
|
||||
sudo make install
|
||||
|
@ -760,7 +760,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
if (literalLength + 1 == optLength) {
|
||||
|
||||
Str2.append("\0", 1); // add null byte
|
||||
addedNull = true;
|
||||
// addedNull = true;
|
||||
|
||||
}
|
||||
|
||||
@ -1111,7 +1111,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
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).",
|
||||
"collisions would be in afl-gcc/vanilla AFL) (%s mode).",
|
||||
inst, calculateCollisions(inst), modeline);
|
||||
|
||||
}
|
||||
@ -1237,6 +1237,25 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
|
||||
StringRef FuncName = Callee->getName();
|
||||
if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
|
||||
|
||||
Value *val = ConstantInt::get(Int32Ty, ++afl_global_id);
|
||||
callInst->setOperand(1, val);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
|
||||
BlocksToInstrument.push_back(&BB);
|
||||
for (auto &Inst : BB) {
|
||||
@ -1338,6 +1357,7 @@ bool ModuleSanitizerCoverage::InjectCoverage(Function & F,
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
CreateFunctionLocalArrays(F, AllBlocks);
|
||||
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||
|
||||
// afl++ START
|
||||
@ -1403,24 +1423,17 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
bool IsEntryBB = &BB == &F.getEntryBlock();
|
||||
DebugLoc EntryLoc;
|
||||
|
||||
if (IsEntryBB) {
|
||||
|
||||
if (auto SP = F.getSubprogram())
|
||||
EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP);
|
||||
// Keep static allocas and llvm.localescape calls in the entry block. Even
|
||||
// if we aren't splitting the block, it's nice for allocas to be before
|
||||
// calls.
|
||||
IP = PrepareToSplitEntryBlock(BB, IP);
|
||||
|
||||
} else {
|
||||
|
||||
EntryLoc = IP->getDebugLoc();
|
||||
|
||||
}
|
||||
|
||||
IRBuilder<> IRB(&*IP);
|
||||
IRB.SetCurrentDebugLocation(EntryLoc);
|
||||
if (Options.TracePC) {
|
||||
|
||||
IRB.CreateCall(SanCovTracePC)
|
||||
|
@ -311,7 +311,8 @@ class ModuleSanitizerCoverage {
|
||||
Function &F, Type *Ty,
|
||||
const char *Section);
|
||||
GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
|
||||
void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks);
|
||||
void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks,
|
||||
uint32_t special);
|
||||
void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
|
||||
bool IsLeafFunc = true);
|
||||
Function *CreateInitCallsForSections(Module &M, const char *CtorName,
|
||||
@ -970,11 +971,11 @@ GlobalVariable *ModuleSanitizerCoverage::CreatePCArray(
|
||||
}
|
||||
|
||||
void ModuleSanitizerCoverage::CreateFunctionLocalArrays(
|
||||
Function &F, ArrayRef<BasicBlock *> AllBlocks) {
|
||||
Function &F, ArrayRef<BasicBlock *> AllBlocks, uint32_t special) {
|
||||
|
||||
if (Options.TracePCGuard)
|
||||
FunctionGuardArray = CreateFunctionLocalArrayInSection(
|
||||
AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName);
|
||||
AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName);
|
||||
|
||||
if (Options.Inline8bitCounters)
|
||||
Function8bitCounterArray = CreateFunctionLocalArrayInSection(
|
||||
@ -993,9 +994,38 @@ bool ModuleSanitizerCoverage::InjectCoverage(Function & F,
|
||||
bool IsLeafFunc) {
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
CreateFunctionLocalArrays(F, AllBlocks);
|
||||
|
||||
uint32_t special = 0;
|
||||
for (auto &BB : F) {
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee) continue;
|
||||
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
|
||||
StringRef FuncName = Callee->getName();
|
||||
if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
|
||||
|
||||
uint32_t id = 1 + instr + (uint32_t)AllBlocks.size() + special++;
|
||||
Value * val = ConstantInt::get(Int32Ty, id);
|
||||
callInst->setOperand(1, val);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, special);
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
|
||||
instr += special;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -1058,7 +1088,7 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch(
|
||||
|
||||
}
|
||||
|
||||
llvm::sort(Initializers.begin() + 2, Initializers.end(),
|
||||
llvm::sort(drop_begin(Initializers, 2),
|
||||
[](const Constant *A, const Constant *B) {
|
||||
|
||||
return cast<ConstantInt>(A)->getLimitedValue() <
|
||||
@ -1106,10 +1136,10 @@ void ModuleSanitizerCoverage::InjectTraceForGep(
|
||||
for (auto GEP : GepTraceTargets) {
|
||||
|
||||
IRBuilder<> IRB(GEP);
|
||||
for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
|
||||
if (!isa<ConstantInt>(*I) && (*I)->getType()->isIntegerTy())
|
||||
for (Use &Idx : GEP->indices())
|
||||
if (!isa<ConstantInt>(Idx) && Idx->getType()->isIntegerTy())
|
||||
IRB.CreateCall(SanCovTraceGepFunction,
|
||||
{IRB.CreateIntCast(*I, IntptrTy, true)});
|
||||
{IRB.CreateIntCast(Idx, IntptrTy, true)});
|
||||
|
||||
}
|
||||
|
||||
@ -1163,24 +1193,18 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
bool IsEntryBB = &BB == &F.getEntryBlock();
|
||||
DebugLoc EntryLoc;
|
||||
|
||||
if (IsEntryBB) {
|
||||
|
||||
if (auto SP = F.getSubprogram())
|
||||
EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP);
|
||||
// Keep static allocas and llvm.localescape calls in the entry block. Even
|
||||
// if we aren't splitting the block, it's nice for allocas to be before
|
||||
// calls.
|
||||
IP = PrepareToSplitEntryBlock(BB, IP);
|
||||
|
||||
} else {
|
||||
|
||||
EntryLoc = IP->getDebugLoc();
|
||||
|
||||
}
|
||||
|
||||
IRBuilder<> IRB(&*IP);
|
||||
IRB.SetCurrentDebugLocation(EntryLoc);
|
||||
|
||||
if (Options.TracePC) {
|
||||
|
||||
IRB.CreateCall(SanCovTracePC);
|
||||
|
@ -70,13 +70,15 @@
|
||||
run. It will end up as .comm, so it shouldn't be too wasteful. */
|
||||
|
||||
#if MAP_SIZE <= 65536
|
||||
#define MAP_INITIAL_SIZE 256000
|
||||
#define MAP_INITIAL_SIZE 2097152
|
||||
#else
|
||||
#define MAP_INITIAL_SIZE MAP_SIZE
|
||||
#endif
|
||||
|
||||
u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
||||
u8 * __afl_area_ptr_dummy = __afl_area_initial;
|
||||
u8 * __afl_area_ptr = __afl_area_initial;
|
||||
u8 * __afl_area_ptr_backup = __afl_area_initial;
|
||||
u8 * __afl_dictionary;
|
||||
u8 * __afl_fuzz_ptr;
|
||||
u32 __afl_fuzz_len_dummy;
|
||||
@ -87,7 +89,12 @@ u32 __afl_map_size = MAP_SIZE;
|
||||
u32 __afl_dictionary_len;
|
||||
u64 __afl_map_addr;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work:
|
||||
int __afl_selective_coverage __attribute__((weak));
|
||||
int __afl_selective_coverage_start_off __attribute__((weak));
|
||||
int __afl_selective_coverage_temp = 1;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||
u32 __afl_prev_ctx;
|
||||
u32 __afl_cmp_counter;
|
||||
@ -100,6 +107,7 @@ __thread u32 __afl_cmp_counter;
|
||||
int __afl_sharedmem_fuzzing __attribute__((weak));
|
||||
|
||||
struct cmp_map *__afl_cmp_map;
|
||||
struct cmp_map *__afl_cmp_map_backup;
|
||||
|
||||
/* Child pid? */
|
||||
|
||||
@ -153,7 +161,7 @@ void send_forkserver_error(int error) {
|
||||
u32 status;
|
||||
if (!error || error > 0xffff) return;
|
||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
|
||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
|
||||
|
||||
}
|
||||
|
||||
@ -230,14 +238,18 @@ static void __afl_map_shm_fuzz() {
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
// if we are not running in afl ensure the map exists
|
||||
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_initial; }
|
||||
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
if (__afl_final_loc % 8)
|
||||
__afl_final_loc = (((__afl_final_loc + 7) >> 3) << 3);
|
||||
if (__afl_final_loc % 64) {
|
||||
|
||||
__afl_final_loc = (((__afl_final_loc + 63) >> 6) << 6);
|
||||
|
||||
}
|
||||
|
||||
__afl_map_size = __afl_final_loc;
|
||||
|
||||
if (__afl_final_loc > MAP_SIZE) {
|
||||
@ -295,11 +307,17 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) {
|
||||
|
||||
if (__afl_map_addr)
|
||||
if (__afl_map_addr) {
|
||||
|
||||
munmap((void *)__afl_map_addr, __afl_final_loc);
|
||||
else
|
||||
|
||||
} else {
|
||||
|
||||
free(__afl_area_ptr);
|
||||
__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
@ -352,7 +370,19 @@ static void __afl_map_shm(void) {
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0);
|
||||
if (__afl_map_size && __afl_map_size > MAP_SIZE) {
|
||||
|
||||
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
|
||||
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = (u8 *)shmat(shm_id, (void *)__afl_map_addr, 0);
|
||||
|
||||
/* Whooooops. */
|
||||
|
||||
@ -379,9 +409,9 @@ static void __afl_map_shm(void) {
|
||||
|
||||
__afl_map_addr) {
|
||||
|
||||
__afl_area_ptr =
|
||||
mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
__afl_area_ptr = (u8 *)mmap(
|
||||
(void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (__afl_area_ptr == MAP_FAILED) {
|
||||
|
||||
@ -396,9 +426,42 @@ static void __afl_map_shm(void) {
|
||||
|
||||
free(__afl_area_ptr);
|
||||
__afl_area_ptr = NULL;
|
||||
if (__afl_final_loc > MAP_INITIAL_SIZE)
|
||||
__afl_area_ptr = malloc(__afl_final_loc);
|
||||
if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
|
||||
|
||||
if (__afl_final_loc > MAP_INITIAL_SIZE) {
|
||||
|
||||
__afl_area_ptr = (u8 *)malloc(__afl_final_loc);
|
||||
|
||||
}
|
||||
|
||||
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr_backup = __afl_area_ptr;
|
||||
|
||||
if (__afl_selective_coverage) {
|
||||
|
||||
if (__afl_map_size > MAP_INITIAL_SIZE) {
|
||||
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_map_size);
|
||||
|
||||
if (__afl_area_ptr_dummy) {
|
||||
|
||||
if (__afl_selective_coverage_start_off) {
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "Error: __afl_selective_coverage failed!\n");
|
||||
__afl_selective_coverage = 0;
|
||||
// continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -446,9 +509,11 @@ static void __afl_map_shm(void) {
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_cmp_map = shmat(shm_id, NULL, 0);
|
||||
__afl_cmp_map = (struct cmp_map *)shmat(shm_id, NULL, 0);
|
||||
#endif
|
||||
|
||||
__afl_cmp_map_backup = __afl_cmp_map;
|
||||
|
||||
if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) {
|
||||
|
||||
perror("shmat for cmplog");
|
||||
@ -483,11 +548,11 @@ static void __afl_start_snapshots(void) {
|
||||
if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
|
||||
memcpy(tmp, &status, 4);
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
|
||||
|
||||
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); }
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
@ -683,7 +748,7 @@ static void __afl_start_forkserver(void) {
|
||||
#endif
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 status = 0;
|
||||
u32 status_for_fsrv = 0;
|
||||
u32 already_read_first = 0;
|
||||
u32 was_killed;
|
||||
|
||||
@ -691,17 +756,26 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
|
||||
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
|
||||
if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
|
||||
if (status) status |= (FS_OPT_ENABLED);
|
||||
memcpy(tmp, &status, 4);
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
|
||||
|
||||
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
|
||||
}
|
||||
|
||||
if (__afl_dictionary_len && __afl_dictionary) {
|
||||
|
||||
status_for_fsrv |= FS_OPT_AUTODICT;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
|
||||
if (status_for_fsrv) { status_for_fsrv |= (FS_OPT_ENABLED); }
|
||||
memcpy(tmp, &status_for_fsrv, 4);
|
||||
|
||||
/* 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;
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
|
||||
|
||||
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
|
||||
|
||||
@ -726,7 +800,6 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
// great lets pass the dictionary through the forkserver FD
|
||||
u32 len = __afl_dictionary_len, offset = 0;
|
||||
s32 ret;
|
||||
|
||||
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
||||
|
||||
@ -738,6 +811,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
s32 ret;
|
||||
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
|
||||
|
||||
if (ret < 1) {
|
||||
@ -894,6 +968,8 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
cycle_cnt = max_cnt;
|
||||
first_pass = 0;
|
||||
__afl_selective_coverage_temp = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
@ -906,6 +982,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||
__afl_selective_coverage_temp = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -915,7 +992,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
||||
follows the loop is not traced. We do that by pivoting back to the
|
||||
dummy output region. */
|
||||
|
||||
__afl_area_ptr = __afl_area_initial;
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
@ -937,7 +1014,7 @@ void __afl_manual_init(void) {
|
||||
init_done = 1;
|
||||
is_persistent = 0;
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_initial;
|
||||
if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
fprintf(stderr,
|
||||
@ -998,7 +1075,12 @@ __attribute__((constructor(1))) void __afl_auto_second(void) {
|
||||
else
|
||||
ptr = (u8 *)malloc(__afl_final_loc);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
|
||||
if (ptr && (ssize_t)ptr != -1) {
|
||||
|
||||
__afl_area_ptr = ptr;
|
||||
__afl_area_ptr_backup = __afl_area_ptr;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1012,9 +1094,14 @@ __attribute__((constructor(0))) void __afl_auto_first(void) {
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr;
|
||||
|
||||
ptr = (u8 *)malloc(1024000);
|
||||
ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr;
|
||||
if (ptr && (ssize_t)ptr != -1) {
|
||||
|
||||
__afl_area_ptr = ptr;
|
||||
__afl_area_ptr_backup = __afl_area_ptr;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1086,8 +1173,9 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
|
||||
fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
|
||||
start, stop);
|
||||
fprintf(stderr,
|
||||
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n",
|
||||
start, stop, (unsigned long)(stop - start));
|
||||
|
||||
}
|
||||
|
||||
@ -1124,22 +1212,33 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
///// CmpLog instrumentation
|
||||
|
||||
void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
|
||||
void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
// fprintf(stderr, "hook1 arg0=%02x arg1=%02x attr=%u\n",
|
||||
// (u8) arg1, (u8) arg2, attr);
|
||||
|
||||
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
// if (!__afl_cmp_map->headers[k].cnt)
|
||||
// __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 0;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 0;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||
@ -1147,20 +1246,36 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
|
||||
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 1;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 1;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (!__afl_cmp_map->headers[k].shape) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||
@ -1168,20 +1283,38 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
|
||||
void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
// fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr);
|
||||
|
||||
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 3;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 3;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 3) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 3;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||
@ -1189,20 +1322,38 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
|
||||
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
// fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr);
|
||||
|
||||
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 7) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||
@ -1210,35 +1361,154 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#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
|
||||
#ifdef WORD_SIZE_64
|
||||
// support for u24 to u120 via llvm _ExitInt(). size is in bytes minus 1
|
||||
void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
|
||||
uint8_t size) {
|
||||
|
||||
#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("__cmplog_ins_hook1")));
|
||||
void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook2")));
|
||||
void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook4")));
|
||||
void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
|
||||
__attribute__((alias("__cmplog_ins_hook8")));
|
||||
// fprintf(stderr, "hookN arg0=%llx:%llx arg1=%llx:%llx bytes=%u attr=%u\n",
|
||||
// (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1,
|
||||
// attr);
|
||||
|
||||
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__) */
|
||||
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
u32 hits;
|
||||
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = size;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < size) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = (u64)arg1;
|
||||
__afl_cmp_map->log[k][hits].v1 = (u64)arg2;
|
||||
|
||||
if (size > 7) {
|
||||
|
||||
__afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64);
|
||||
__afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
u32 hits;
|
||||
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 15;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 15) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 15;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = attr;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = (u64)arg1;
|
||||
__afl_cmp_map->log[k][hits].v1 = (u64)arg2;
|
||||
__afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64);
|
||||
__afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
|
||||
|
||||
__cmplog_ins_hook1(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) {
|
||||
|
||||
__cmplog_ins_hook1(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
|
||||
|
||||
__cmplog_ins_hook2(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) {
|
||||
|
||||
__cmplog_ins_hook2(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
|
||||
|
||||
__cmplog_ins_hook4(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cost_cmp4(uint32_t arg1, uint32_t arg2) {
|
||||
|
||||
__cmplog_ins_hook4(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
__cmplog_ins_hook8(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) {
|
||||
|
||||
__cmplog_ins_hook8(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
#ifdef WORD_SIZE_64
|
||||
void __sanitizer_cov_trace_cmp16(uint128_t arg1, uint128_t arg2) {
|
||||
|
||||
__cmplog_ins_hook16(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
@ -1250,12 +1520,28 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 7) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 7;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__afl_cmp_map->headers[k].attribute = 1;
|
||||
|
||||
hits &= CMP_MAP_H - 1;
|
||||
__afl_cmp_map->log[k][hits].v0 = val;
|
||||
@ -1270,7 +1556,7 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
// to avoid to call it on .text addresses
|
||||
static int area_is_mapped(void *ptr, size_t len) {
|
||||
|
||||
char *p = ptr;
|
||||
char *p = (char *)ptr;
|
||||
char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1));
|
||||
|
||||
int r = msync(page, (p - page) + len, MS_ASYNC);
|
||||
@ -1281,6 +1567,18 @@ static int area_is_mapped(void *ptr, size_t len) {
|
||||
|
||||
void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
|
||||
/*
|
||||
u32 i;
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
fprintf(stderr, "rtn arg0=");
|
||||
for (i = 0; i < 24; i++)
|
||||
fprintf(stderr, "%02x", ptr1[i]);
|
||||
fprintf(stderr, " arg1=");
|
||||
for (i = 0; i < 24; i++)
|
||||
fprintf(stderr, "%02x", ptr2[i]);
|
||||
fprintf(stderr, "\n");
|
||||
*/
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
@ -1289,12 +1587,26 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
|
||||
u32 hits;
|
||||
|
||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 31) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hits &= CMP_MAP_RTN_H - 1;
|
||||
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
|
||||
@ -1304,3 +1616,148 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
|
||||
}
|
||||
|
||||
// gcc libstdc++
|
||||
// _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
|
||||
static u8 *get_gcc_stdstring(u8 *string) {
|
||||
|
||||
u32 *len = (u32 *)(string + 8);
|
||||
|
||||
if (*len < 16) { // in structure
|
||||
|
||||
return (string + 16);
|
||||
|
||||
} else { // in memory
|
||||
|
||||
u8 **ptr = (u8 **)string;
|
||||
return (*ptr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// llvm libc++ _ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocator
|
||||
// IcEEE7compareEmmPKcm
|
||||
static u8 *get_llvm_stdstring(u8 *string) {
|
||||
|
||||
// length is in: if ((string[0] & 1) == 0) u8 len = (string[0] >> 1);
|
||||
// or: if (string[0] & 1) u32 *len = (u32 *) (string + 8);
|
||||
|
||||
if (string[0] & 1) { // in memory
|
||||
|
||||
u8 **ptr = (u8 **)(string + 16);
|
||||
return (*ptr);
|
||||
|
||||
} else { // in structure
|
||||
|
||||
return (string + 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
|
||||
get_gcc_stdstring(stdstring2));
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
|
||||
|
||||
}
|
||||
|
||||
void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring1),
|
||||
get_llvm_stdstring(stdstring2));
|
||||
|
||||
}
|
||||
|
||||
/* COVERAGE manipulation features */
|
||||
|
||||
// this variable is then used in the shm setup to create an additional map
|
||||
// if __afl_map_size > MAP_SIZE or cmplog is used.
|
||||
// Especially with cmplog this would result in a ~260MB mem increase per
|
||||
// target run.
|
||||
|
||||
// disable coverage from this point onwards until turned on again
|
||||
void __afl_coverage_off() {
|
||||
|
||||
if (likely(__afl_selective_coverage)) {
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
__afl_cmp_map = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// enable coverage
|
||||
void __afl_coverage_on() {
|
||||
|
||||
if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) {
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_backup;
|
||||
__afl_cmp_map = __afl_cmp_map_backup;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// discard all coverage up to this point
|
||||
void __afl_coverage_discard() {
|
||||
|
||||
memset(__afl_area_ptr_backup, 0, __afl_map_size);
|
||||
__afl_area_ptr_backup[0] = 1;
|
||||
|
||||
if (__afl_cmp_map) { memset(__afl_cmp_map, 0, sizeof(struct cmp_map)); }
|
||||
|
||||
}
|
||||
|
||||
// discard the testcase
|
||||
void __afl_coverage_skip() {
|
||||
|
||||
__afl_coverage_discard();
|
||||
|
||||
if (likely(is_persistent && __afl_selective_coverage)) {
|
||||
|
||||
__afl_coverage_off();
|
||||
__afl_selective_coverage_temp = 0;
|
||||
|
||||
} else {
|
||||
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// mark this area as especially interesting
|
||||
void __afl_coverage_interesting(u8 val, u32 id) {
|
||||
|
||||
__afl_area_ptr[id] = val;
|
||||
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ struct afl_pass : gimple_opt_pass {
|
||||
const bool neverZero;
|
||||
|
||||
/* Count instrumented blocks. */
|
||||
int inst_blocks;
|
||||
unsigned int inst_blocks;
|
||||
|
||||
virtual unsigned int execute(function *fn) {
|
||||
|
||||
@ -444,8 +444,10 @@ struct afl_pass : gimple_opt_pass {
|
||||
DECL_EXTERNAL(decl) = 1;
|
||||
DECL_ARTIFICIAL(decl) = 1;
|
||||
TREE_STATIC(decl) = 1;
|
||||
#if !defined(__ANDROID__) && !defined(__HAIKU__)
|
||||
set_decl_tls_model(
|
||||
decl, (flag_pic ? TLS_MODEL_INITIAL_EXEC : TLS_MODEL_LOCAL_EXEC));
|
||||
#endif
|
||||
return decl;
|
||||
|
||||
}
|
||||
@ -516,7 +518,9 @@ struct afl_pass : gimple_opt_pass {
|
||||
"__cmplog",
|
||||
"__sancov",
|
||||
"msan.",
|
||||
"LLVMFuzzer",
|
||||
"LLVMFuzzerM",
|
||||
"LLVMFuzzerC",
|
||||
"LLVMFuzzerI",
|
||||
"__decide_deferred",
|
||||
"maybe_duplicate_stderr",
|
||||
"discard_output",
|
||||
@ -620,10 +624,11 @@ struct afl_pass : gimple_opt_pass {
|
||||
allowListFiles.push_back(line);
|
||||
else
|
||||
allowListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
@ -694,10 +699,11 @@ struct afl_pass : gimple_opt_pass {
|
||||
denyListFiles.push_back(line);
|
||||
else
|
||||
denyListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
@ -916,8 +922,9 @@ int plugin_init(struct plugin_name_args * info,
|
||||
struct plugin_gcc_version *version) {
|
||||
|
||||
if (!plugin_default_version_check(version, &gcc_version))
|
||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %d.%d"),
|
||||
GCCPLUGIN_VERSION_MAJOR, GCCPLUGIN_VERSION_MINOR);
|
||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
|
||||
"is %s"),
|
||||
gcc_version.basever, version->basever);
|
||||
|
||||
/* Show a banner. */
|
||||
bool quiet = false;
|
||||
@ -927,7 +934,7 @@ int plugin_init(struct plugin_name_args * info,
|
||||
quiet = true;
|
||||
|
||||
/* Decide instrumentation ratio. */
|
||||
int inst_ratio = 100;
|
||||
unsigned int inst_ratio = 100U;
|
||||
if (char *inst_ratio_str = getenv("AFL_INST_RATIO"))
|
||||
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
|
||||
inst_ratio > 100)
|
||||
|
@ -70,7 +70,9 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
"__cmplog",
|
||||
"__sancov",
|
||||
"msan.",
|
||||
"LLVMFuzzer",
|
||||
"LLVMFuzzerM",
|
||||
"LLVMFuzzerC",
|
||||
"LLVMFuzzerI",
|
||||
"__decide_deferred",
|
||||
"maybe_duplicate_stderr",
|
||||
"discard_output",
|
||||
@ -166,10 +168,11 @@ void initInstrumentList() {
|
||||
allowListFiles.push_back(line);
|
||||
else
|
||||
allowListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
@ -240,10 +243,11 @@ void initInstrumentList() {
|
||||
denyListFiles.push_back(line);
|
||||
else
|
||||
denyListFunctions.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
if (debug)
|
||||
@ -347,7 +351,7 @@ static std::string getSourceName(llvm::Function *F) {
|
||||
|
||||
if (cDILoc) { instFilename = cDILoc->getFilename(); }
|
||||
|
||||
if (instFilename.str().empty()) {
|
||||
if (instFilename.str().empty() && cDILoc) {
|
||||
|
||||
/* If the original location is empty, try using the inlined location
|
||||
*/
|
||||
|
@ -90,7 +90,7 @@ void dict2file(int fd, u8 *mem, u32 len) {
|
||||
j = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (isprint(mem[i])) {
|
||||
if (isprint(mem[i]) && mem[i] != '\\' && mem[i] != '"') {
|
||||
|
||||
line[j++] = mem[i];
|
||||
|
||||
@ -355,7 +355,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
*Str2P = callInst->getArgOperand(1);
|
||||
std::string Str1, Str2;
|
||||
StringRef TmpStr;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
|
||||
bool HasStr1;
|
||||
getConstantStringInfo(Str1P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr1 = false;
|
||||
@ -367,7 +368,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
|
||||
bool HasStr2;
|
||||
getConstantStringInfo(Str2P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr2 = false;
|
||||
@ -428,7 +430,6 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
if (literalLength + 1 == optLength) {
|
||||
|
||||
Str2.append("\0", 1); // add null byte
|
||||
addedNull = true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -69,8 +69,9 @@ class AFLLTOPass : public ModulePass {
|
||||
|
||||
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",
|
||||
if ((afl_global_id = (uint32_t)atoi(ptr)) < 0 ||
|
||||
afl_global_id >= MAP_SIZE)
|
||||
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %u\n",
|
||||
ptr, MAP_SIZE - 1);
|
||||
|
||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||
@ -88,7 +89,7 @@ class AFLLTOPass : public ModulePass {
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
protected:
|
||||
int afl_global_id = 1, autodictionary = 1;
|
||||
uint32_t afl_global_id = 1, autodictionary = 1;
|
||||
uint32_t function_minimum_size = 1;
|
||||
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
||||
uint64_t map_addr = 0x10000;
|
||||
@ -100,9 +101,9 @@ class AFLLTOPass : public ModulePass {
|
||||
|
||||
bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
LLVMContext & C = M.getContext();
|
||||
std::vector<std::string> dictionary;
|
||||
std::vector<CallInst *> calls;
|
||||
LLVMContext & C = M.getContext();
|
||||
std::vector<std::string> dictionary;
|
||||
// std::vector<CallInst *> calls;
|
||||
DenseMap<Value *, std::string *> valueMap;
|
||||
std::vector<BasicBlock *> BlockList;
|
||||
char * ptr;
|
||||
@ -471,7 +472,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
*Str2P = callInst->getArgOperand(1);
|
||||
std::string Str1, Str2;
|
||||
StringRef TmpStr;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
|
||||
bool HasStr1;
|
||||
getConstantStringInfo(Str1P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr1 = false;
|
||||
@ -483,7 +485,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
|
||||
bool HasStr2;
|
||||
getConstantStringInfo(Str2P, TmpStr);
|
||||
if (TmpStr.empty()) {
|
||||
|
||||
HasStr2 = false;
|
||||
@ -543,7 +546,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
if (literalLength + 1 == optLength) {
|
||||
|
||||
Str2.append("\0", 1); // add null byte
|
||||
addedNull = true;
|
||||
// addedNull = true;
|
||||
|
||||
}
|
||||
|
||||
@ -671,7 +674,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
std::string outstring;
|
||||
fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
|
||||
thestring.length());
|
||||
for (uint8_t i = 0; i < thestring.length(); i++) {
|
||||
@ -872,7 +874,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
pow2map++;
|
||||
WARNF(
|
||||
"We have %u blocks to instrument but the map size is only %u. Either "
|
||||
"edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
|
||||
"edit config.h and set MAP_SIZE_POW2 from %d to %u, then recompile "
|
||||
"afl-fuzz and llvm_mode and then make this target - or set "
|
||||
"AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
|
||||
"target.",
|
||||
@ -922,9 +924,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
|
||||
|
||||
uint32_t write_loc = afl_global_id;
|
||||
|
||||
if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
|
||||
uint32_t write_loc = (((afl_global_id + 63) >> 6) << 6);
|
||||
|
||||
GlobalVariable *AFLFinalLoc = new GlobalVariable(
|
||||
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc");
|
||||
@ -937,8 +937,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
if (dictionary.size()) {
|
||||
|
||||
size_t memlen = 0, count = 0, offset = 0;
|
||||
char * ptr;
|
||||
size_t memlen = 0, count = 0;
|
||||
|
||||
// sort and unique the dictionary
|
||||
std::sort(dictionary.begin(), dictionary.end());
|
||||
@ -953,14 +952,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
}
|
||||
|
||||
if (!be_quiet)
|
||||
printf("AUTODICTIONARY: %lu string%s found\n", count,
|
||||
printf("AUTODICTIONARY: %zu string%s found\n", count,
|
||||
count == 1 ? "" : "s");
|
||||
|
||||
if (count) {
|
||||
|
||||
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
|
||||
|
||||
fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
|
||||
fprintf(stderr, "Error: malloc for %zu bytes failed!\n",
|
||||
memlen + count);
|
||||
exit(-1);
|
||||
|
||||
@ -968,6 +967,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
|
||||
count = 0;
|
||||
|
||||
size_t offset = 0;
|
||||
for (auto token : dictionary) {
|
||||
|
||||
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
|
||||
@ -1031,8 +1031,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
||||
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).",
|
||||
OKF("Instrumented %d locations with no collisions (on average %llu "
|
||||
"collisions would be in afl-gcc/vanilla AFL) (%s mode).",
|
||||
inst_blocks, calculateCollisions(inst_blocks), modeline);
|
||||
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
GlobalVariable *AFLContext = NULL;
|
||||
|
||||
if (ctx_str)
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||
#else
|
||||
@ -252,7 +252,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||
@ -265,7 +265,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||
#else
|
||||
@ -327,10 +327,10 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
// does the function have calls? and is any of the calls larger than one
|
||||
// basic block?
|
||||
for (auto &BB : F) {
|
||||
for (auto &BB_2 : F) {
|
||||
|
||||
if (has_calls) break;
|
||||
for (auto &IN : BB) {
|
||||
for (auto &IN : BB_2) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -538,6 +538,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
|
||||
AFLPrevLoc);
|
||||
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
}
|
||||
|
||||
@ -628,7 +629,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
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,
|
||||
OKF("Instrumented %d locations (%s mode, ratio %u%%).", inst_blocks,
|
||||
modeline, inst_ratio);
|
||||
|
||||
}
|
||||
|
@ -19,12 +19,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sys/time.h>
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
@ -85,9 +86,25 @@ class CmpLogInstructions : public ModulePass {
|
||||
|
||||
char CmpLogInstructions::ID = 0;
|
||||
|
||||
template <class Iterator>
|
||||
Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
while (first != last) {
|
||||
|
||||
Iterator next(first);
|
||||
last = std::remove(++next, last, *first);
|
||||
first = next;
|
||||
|
||||
}
|
||||
|
||||
return last;
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
|
||||
std::vector<Instruction *> icomps;
|
||||
std::vector<SwitchInst *> switches;
|
||||
LLVMContext & C = M.getContext();
|
||||
|
||||
Type * VoidTy = Type::getVoidTy(C);
|
||||
@ -95,13 +112,15 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||
IntegerType *Int128Ty = IntegerType::getInt128Ty(C);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty
|
||||
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
@ -118,7 +137,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty
|
||||
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
@ -135,7 +155,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty
|
||||
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
@ -152,7 +173,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty
|
||||
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
@ -164,6 +186,42 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
FunctionCallee cmplogHookIns8 = c8;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy, Int128Ty,
|
||||
Int128Ty, Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns16 = cast<Function>(c16);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns16 = c16;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy, Int128Ty,
|
||||
Int128Ty, Int8Ty, Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookInsN = cast<Function>(cN);
|
||||
#else
|
||||
FunctionCallee cmplogHookInsN = cN;
|
||||
#endif
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||
for (auto &F : M) {
|
||||
|
||||
@ -174,30 +232,165 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
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) {
|
||||
icomps.push_back(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());
|
||||
SwitchInst *switchInst = nullptr;
|
||||
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
|
||||
|
||||
/* this is probably not needed but we do it anyway */
|
||||
if (!intTyOp0 || !intTyOp1) { continue; }
|
||||
if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); }
|
||||
|
||||
icomps.push_back(selectcmpInst);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// unique the collected switches
|
||||
switches.erase(Unique(switches.begin(), switches.end()), switches.end());
|
||||
|
||||
// Instrument switch values for cmplog
|
||||
if (switches.size()) {
|
||||
|
||||
if (!be_quiet)
|
||||
errs() << "Hooking " << switches.size() << " switch instructions\n";
|
||||
|
||||
for (auto &SI : switches) {
|
||||
|
||||
Value * Val = SI->getCondition();
|
||||
unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size;
|
||||
unsigned char do_cast = 0;
|
||||
|
||||
if (!SI->getNumCases() || max_size < 16) {
|
||||
|
||||
// if (!be_quiet) errs() << "skip trivial switch..\n";
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (max_size % 8) {
|
||||
|
||||
max_size = (((max_size / 8) + 1) * 8);
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
IRBuilder<> IRB(SI->getParent());
|
||||
IRB.SetInsertPoint(SI);
|
||||
|
||||
if (max_size > 128) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Cannot handle this switch bit size: %u (truncating)\n",
|
||||
max_size);
|
||||
|
||||
}
|
||||
|
||||
max_size = 128;
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
// do we need to cast?
|
||||
switch (max_size) {
|
||||
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
cast_size = max_size;
|
||||
break;
|
||||
default:
|
||||
cast_size = 128;
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
Value *CompareTo = Val;
|
||||
|
||||
if (do_cast) {
|
||||
|
||||
CompareTo =
|
||||
IRB.CreateIntCast(CompareTo, IntegerType::get(C, cast_size), false);
|
||||
|
||||
}
|
||||
|
||||
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
|
||||
++i) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
ConstantInt *cint = i.getCaseValue();
|
||||
#else
|
||||
ConstantInt *cint = i->getCaseValue();
|
||||
#endif
|
||||
|
||||
if (cint) {
|
||||
|
||||
std::vector<Value *> args;
|
||||
args.push_back(CompareTo);
|
||||
|
||||
Value *new_param = cint;
|
||||
|
||||
if (do_cast) {
|
||||
|
||||
new_param =
|
||||
IRB.CreateIntCast(cint, IntegerType::get(C, cast_size), false);
|
||||
|
||||
}
|
||||
|
||||
if (new_param) {
|
||||
|
||||
args.push_back(new_param);
|
||||
ConstantInt *attribute = ConstantInt::get(Int8Ty, 1);
|
||||
args.push_back(attribute);
|
||||
if (cast_size != max_size) {
|
||||
|
||||
ConstantInt *bitsize =
|
||||
ConstantInt::get(Int8Ty, (max_size / 8) - 1);
|
||||
args.push_back(bitsize);
|
||||
|
||||
}
|
||||
|
||||
switch (cast_size) {
|
||||
|
||||
case 8:
|
||||
IRB.CreateCall(cmplogHookIns1, args);
|
||||
break;
|
||||
case 16:
|
||||
IRB.CreateCall(cmplogHookIns2, args);
|
||||
break;
|
||||
case 32:
|
||||
IRB.CreateCall(cmplogHookIns4, args);
|
||||
break;
|
||||
case 64:
|
||||
IRB.CreateCall(cmplogHookIns8, args);
|
||||
break;
|
||||
case 128:
|
||||
#ifdef WORD_SIZE_64
|
||||
if (max_size == 128) {
|
||||
|
||||
IRB.CreateCall(cmplogHookIns16, args);
|
||||
|
||||
} else {
|
||||
|
||||
IRB.CreateCall(cmplogHookInsN, args);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -209,51 +402,217 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (!icomps.size()) return false;
|
||||
// if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp
|
||||
// instructions\n";
|
||||
if (icomps.size()) {
|
||||
|
||||
for (auto &selectcmpInst : icomps) {
|
||||
// if (!be_quiet) errs() << "Hooking " << icomps.size() <<
|
||||
// " cmp instructions\n";
|
||||
|
||||
IRBuilder<> IRB(selectcmpInst->getParent());
|
||||
IRB.SetInsertPoint(selectcmpInst);
|
||||
for (auto &selectcmpInst : icomps) {
|
||||
|
||||
auto op0 = selectcmpInst->getOperand(0);
|
||||
auto op1 = selectcmpInst->getOperand(1);
|
||||
IRBuilder<> IRB(selectcmpInst->getParent());
|
||||
IRB.SetInsertPoint(selectcmpInst);
|
||||
|
||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
||||
Value *op0 = selectcmpInst->getOperand(0);
|
||||
Value *op1 = selectcmpInst->getOperand(1);
|
||||
|
||||
unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
|
||||
? intTyOp0->getBitWidth()
|
||||
: intTyOp1->getBitWidth();
|
||||
IntegerType * intTyOp0 = NULL;
|
||||
IntegerType * intTyOp1 = NULL;
|
||||
unsigned max_size = 0, cast_size = 0;
|
||||
unsigned char attr = 0, do_cast = 0;
|
||||
std::vector<Value *> args;
|
||||
|
||||
std::vector<Value *> args;
|
||||
args.push_back(op0);
|
||||
args.push_back(op1);
|
||||
CmpInst *cmpInst = dyn_cast<CmpInst>(selectcmpInst);
|
||||
|
||||
switch (max_size) {
|
||||
if (!cmpInst) { continue; }
|
||||
|
||||
case 8:
|
||||
IRB.CreateCall(cmplogHookIns1, args);
|
||||
break;
|
||||
case 16:
|
||||
IRB.CreateCall(cmplogHookIns2, args);
|
||||
break;
|
||||
case 32:
|
||||
IRB.CreateCall(cmplogHookIns4, args);
|
||||
break;
|
||||
case 64:
|
||||
IRB.CreateCall(cmplogHookIns8, args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (cmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::ICMP_NE:
|
||||
case CmpInst::FCMP_UNE:
|
||||
case CmpInst::FCMP_ONE:
|
||||
break;
|
||||
case CmpInst::ICMP_EQ:
|
||||
case CmpInst::FCMP_UEQ:
|
||||
case CmpInst::FCMP_OEQ:
|
||||
attr += 1;
|
||||
break;
|
||||
case CmpInst::ICMP_UGT:
|
||||
case CmpInst::ICMP_SGT:
|
||||
case CmpInst::FCMP_OGT:
|
||||
case CmpInst::FCMP_UGT:
|
||||
attr += 2;
|
||||
break;
|
||||
case CmpInst::ICMP_UGE:
|
||||
case CmpInst::ICMP_SGE:
|
||||
case CmpInst::FCMP_OGE:
|
||||
case CmpInst::FCMP_UGE:
|
||||
attr += 3;
|
||||
break;
|
||||
case CmpInst::ICMP_ULT:
|
||||
case CmpInst::ICMP_SLT:
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT:
|
||||
attr += 4;
|
||||
break;
|
||||
case CmpInst::ICMP_ULE:
|
||||
case CmpInst::ICMP_SLE:
|
||||
case CmpInst::FCMP_OLE:
|
||||
case CmpInst::FCMP_ULE:
|
||||
attr += 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (selectcmpInst->getOpcode() == Instruction::FCmp) {
|
||||
|
||||
auto ty0 = op0->getType();
|
||||
if (ty0->isHalfTy()
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
|| ty0->isBFloatTy()
|
||||
#endif
|
||||
)
|
||||
max_size = 16;
|
||||
else if (ty0->isFloatTy())
|
||||
max_size = 32;
|
||||
else if (ty0->isDoubleTy())
|
||||
max_size = 64;
|
||||
else if (ty0->isX86_FP80Ty())
|
||||
max_size = 80;
|
||||
else if (ty0->isFP128Ty() || ty0->isPPC_FP128Ty())
|
||||
max_size = 128;
|
||||
|
||||
attr += 8;
|
||||
do_cast = 1;
|
||||
|
||||
} else {
|
||||
|
||||
intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||
intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
||||
|
||||
if (intTyOp0 && intTyOp1) {
|
||||
|
||||
max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
|
||||
? intTyOp0->getBitWidth()
|
||||
: intTyOp1->getBitWidth();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!max_size || max_size < 16) { continue; }
|
||||
|
||||
if (max_size % 8) {
|
||||
|
||||
max_size = (((max_size / 8) + 1) * 8);
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
if (max_size > 128) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Cannot handle this compare bit size: %u (truncating)\n",
|
||||
max_size);
|
||||
|
||||
}
|
||||
|
||||
max_size = 128;
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
// do we need to cast?
|
||||
switch (max_size) {
|
||||
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
cast_size = max_size;
|
||||
break;
|
||||
default:
|
||||
cast_size = 128;
|
||||
do_cast = 1;
|
||||
|
||||
}
|
||||
|
||||
// errs() << "[CMPLOG] cmp " << *cmpInst << "(in function " <<
|
||||
// cmpInst->getFunction()->getName() << ")\n";
|
||||
|
||||
// first bitcast to integer type of the same bitsize as the original
|
||||
// type (this is a nop, if already integer)
|
||||
Value *op0_i = IRB.CreateBitCast(
|
||||
op0, IntegerType::get(C, op0->getType()->getPrimitiveSizeInBits()));
|
||||
// then create a int cast, which does zext, trunc or bitcast. In our case
|
||||
// usually zext to the next larger supported type (this is a nop if
|
||||
// already the right type)
|
||||
Value *V0 =
|
||||
IRB.CreateIntCast(op0_i, IntegerType::get(C, cast_size), false);
|
||||
args.push_back(V0);
|
||||
Value *op1_i = IRB.CreateBitCast(
|
||||
op1, IntegerType::get(C, op1->getType()->getPrimitiveSizeInBits()));
|
||||
Value *V1 =
|
||||
IRB.CreateIntCast(op1_i, IntegerType::get(C, cast_size), false);
|
||||
args.push_back(V1);
|
||||
|
||||
// errs() << "[CMPLOG] casted parameters:\n0: " << *V0 << "\n1: " << *V1
|
||||
// << "\n";
|
||||
|
||||
ConstantInt *attribute = ConstantInt::get(Int8Ty, attr);
|
||||
args.push_back(attribute);
|
||||
|
||||
if (cast_size != max_size) {
|
||||
|
||||
ConstantInt *bitsize = ConstantInt::get(Int8Ty, (max_size / 8) - 1);
|
||||
args.push_back(bitsize);
|
||||
|
||||
}
|
||||
|
||||
// fprintf(stderr, "_ExtInt(%u) castTo %u with attr %u didcast %u\n",
|
||||
// max_size, cast_size, attr, do_cast);
|
||||
|
||||
switch (cast_size) {
|
||||
|
||||
case 8:
|
||||
IRB.CreateCall(cmplogHookIns1, args);
|
||||
break;
|
||||
case 16:
|
||||
IRB.CreateCall(cmplogHookIns2, args);
|
||||
break;
|
||||
case 32:
|
||||
IRB.CreateCall(cmplogHookIns4, args);
|
||||
break;
|
||||
case 64:
|
||||
IRB.CreateCall(cmplogHookIns8, args);
|
||||
break;
|
||||
case 128:
|
||||
if (max_size == 128) {
|
||||
|
||||
IRB.CreateCall(cmplogHookIns16, args);
|
||||
|
||||
} else {
|
||||
|
||||
IRB.CreateCall(cmplogHookInsN, args);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
if (switches.size() || icomps.size())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ char CmpLogRoutines::ID = 0;
|
||||
|
||||
bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
std::vector<CallInst *> calls;
|
||||
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC;
|
||||
LLVMContext & C = M.getContext();
|
||||
|
||||
Type *VoidTy = Type::getVoidTy(C);
|
||||
@ -112,6 +112,78 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
FunctionCallee cmplogHookFn = c;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
|
||||
VoidTy, i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogLlvmStdStd = cast<Function>(c1);
|
||||
#else
|
||||
FunctionCallee cmplogLlvmStdStd = c1;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogLlvmStdC = cast<Function>(c2);
|
||||
#else
|
||||
FunctionCallee cmplogLlvmStdC = c2;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogGccStdStd = cast<Function>(c3);
|
||||
#else
|
||||
FunctionCallee cmplogGccStdStd = c3;
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogGccStdC = cast<Function>(c4);
|
||||
#else
|
||||
FunctionCallee cmplogGccStdC = c4;
|
||||
#endif
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||
for (auto &F : M) {
|
||||
|
||||
@ -136,9 +208,64 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0)->isPointerTy();
|
||||
|
||||
if (!isPtrRtn) continue;
|
||||
bool isGccStdStringStdString =
|
||||
Callee->getName().find("__is_charIT_EE7__value") !=
|
||||
std::string::npos &&
|
||||
Callee->getName().find(
|
||||
"St7__cxx1112basic_stringIS2_St11char_traits") !=
|
||||
std::string::npos &&
|
||||
FT->getNumParams() >= 2 &&
|
||||
FT->getParamType(0) == FT->getParamType(1) &&
|
||||
FT->getParamType(0)->isPointerTy();
|
||||
|
||||
calls.push_back(callInst);
|
||||
bool isGccStdStringCString =
|
||||
Callee->getName().find(
|
||||
"St7__cxx1112basic_stringIcSt11char_"
|
||||
"traitsIcESaIcEE7compareEPK") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
bool isLlvmStdStringStdString =
|
||||
Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
|
||||
Callee->getName().find("_12basic_stringI") != std::string::npos &&
|
||||
Callee->getName().find("_11char_traits") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
bool isLlvmStdStringCString =
|
||||
Callee->getName().find("_ZNSt3__1eqI") != std::string::npos &&
|
||||
Callee->getName().find("_12basic_stringI") != std::string::npos &&
|
||||
FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() &&
|
||||
FT->getParamType(1)->isPointerTy();
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
fprintf(stderr, "F:%s C:%s argc:%u\n",
|
||||
F.getName().str().c_str(),
|
||||
Callee->getName().str().c_str(), FT->getNumParams());
|
||||
fprintf(stderr, "ptr0:%u ptr1:%u ptr2:%u\n",
|
||||
FT->getParamType(0)->isPointerTy(),
|
||||
FT->getParamType(1)->isPointerTy(),
|
||||
FT->getNumParams() > 2 ?
|
||||
FT->getParamType(2)->isPointerTy() : 22 );
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (isGccStdStringCString || isGccStdStringStdString ||
|
||||
isLlvmStdStringStdString || isLlvmStdStringCString) {
|
||||
|
||||
isPtrRtn = false;
|
||||
|
||||
}
|
||||
|
||||
if (isPtrRtn) { calls.push_back(callInst); }
|
||||
if (isGccStdStringStdString) { gccStdStd.push_back(callInst); }
|
||||
if (isGccStdStringCString) { gccStdC.push_back(callInst); }
|
||||
if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
|
||||
if (isLlvmStdStringCString) { llvmStdC.push_back(callInst); }
|
||||
|
||||
}
|
||||
|
||||
@ -148,7 +275,10 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
if (!calls.size()) return false;
|
||||
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
|
||||
!llvmStdStd.size() && !llvmStdC.size())
|
||||
return false;
|
||||
|
||||
/*
|
||||
if (!be_quiet)
|
||||
errs() << "Hooking " << calls.size()
|
||||
@ -174,6 +304,82 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : gccStdStd) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogGccStdStd, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : gccStdC) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogGccStdC, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : llvmStdStd) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogLlvmStdStd, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
for (auto &callInst : llvmStdC) {
|
||||
|
||||
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
|
||||
|
||||
IRBuilder<> IRB(callInst->getParent());
|
||||
IRB.SetInsertPoint(callInst);
|
||||
|
||||
std::vector<Value *> args;
|
||||
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
|
||||
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
|
||||
args.push_back(v1Pcasted);
|
||||
args.push_back(v2Pcasted);
|
||||
|
||||
IRB.CreateCall(cmplogLlvmStdC, args);
|
||||
|
||||
// errs() << callInst->getCalledFunction()->getName() << "\n";
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class CompareTransform : public ModulePass {
|
||||
const char *getPassName() const override {
|
||||
|
||||
#else
|
||||
StringRef getPassName() const override {
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "transforms compare functions";
|
||||
@ -101,21 +101,30 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Constant *
|
||||
Function *tolowerFn;
|
||||
#else
|
||||
FunctionCallee
|
||||
FunctionCallee tolowerFn;
|
||||
#endif
|
||||
c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
{
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *tolowerFn = cast<Function>(c);
|
||||
Constant *
|
||||
#else
|
||||
FunctionCallee tolowerFn = c;
|
||||
FunctionCallee
|
||||
#endif
|
||||
c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
tolowerFn = cast<Function>(c);
|
||||
#else
|
||||
tolowerFn = c;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add suitable calls to
|
||||
* strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
|
||||
@ -234,7 +243,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
|
||||
if (!HasStr2) {
|
||||
|
||||
auto *Ptr = dyn_cast<ConstantExpr>(Str1P);
|
||||
Ptr = dyn_cast<ConstantExpr>(Str1P);
|
||||
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
|
||||
|
||||
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
|
||||
@ -353,19 +362,22 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
uint64_t constStrLen, unrollLen, constSizedLen = 0;
|
||||
bool isMemcmp =
|
||||
!callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
|
||||
bool isSizedcmp = isMemcmp ||
|
||||
!callInst->getCalledFunction()->getName().compare(
|
||||
StringRef("strncmp")) ||
|
||||
!callInst->getCalledFunction()->getName().compare(
|
||||
StringRef("strncasecmp"));
|
||||
bool isMemcmp = false;
|
||||
bool isSizedcmp = false;
|
||||
bool isCaseInsensitive = false;
|
||||
Function * Callee = callInst->getCalledFunction();
|
||||
if (Callee) {
|
||||
|
||||
isMemcmp = Callee->getName().compare("memcmp") == 0;
|
||||
isSizedcmp = isMemcmp || Callee->getName().compare("strncmp") == 0 ||
|
||||
Callee->getName().compare("strncasecmp") == 0;
|
||||
isCaseInsensitive = Callee->getName().compare("strcasecmp") == 0 ||
|
||||
Callee->getName().compare("strncasecmp") == 0;
|
||||
|
||||
}
|
||||
|
||||
Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL;
|
||||
bool isConstSized = sizedValue && isa<ConstantInt>(sizedValue);
|
||||
bool isCaseInsensitive = !callInst->getCalledFunction()->getName().compare(
|
||||
StringRef("strcasecmp")) ||
|
||||
!callInst->getCalledFunction()->getName().compare(
|
||||
StringRef("strncasecmp"));
|
||||
|
||||
if (!(HasStr1 || HasStr2)) {
|
||||
|
||||
@ -382,7 +394,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
if (val && !val->empty()) {
|
||||
|
||||
Str2 = StringRef(*val);
|
||||
HasStr2 = true;
|
||||
// HasStr2 = true;
|
||||
|
||||
}
|
||||
|
||||
@ -427,15 +439,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
||||
else
|
||||
unrollLen = constStrLen;
|
||||
|
||||
/*
|
||||
if (!be_quiet)
|
||||
errs() << callInst->getCalledFunction()->getName() << ": unroll len "
|
||||
<< unrollLen
|
||||
<< ((isSizedcmp && !isConstSized) ? ", variable n" : "") << ":
|
||||
"
|
||||
<< ConstStr << "\n";
|
||||
*/
|
||||
|
||||
/* split before the call instruction */
|
||||
BasicBlock *bb = callInst->getParent();
|
||||
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst));
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef AFL_NGRAM_CONFIG_H
|
||||
#define AFL_NGRAM_CONFIG_H
|
||||
|
||||
#include "../config.h"
|
||||
#include "types.h"
|
||||
|
||||
#if (MAP_SIZE_POW2 <= 16)
|
||||
typedef u16 PREV_LOC_T;
|
||||
|
@ -53,7 +53,7 @@ class SplitComparesTransform : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
SplitComparesTransform() : ModulePass(ID) {
|
||||
SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
@ -407,6 +407,7 @@ bool SplitComparesTransform::simplifyIntSignedness(Module &M) {
|
||||
auto op1 = IcmpInst->getOperand(1);
|
||||
|
||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||
if (!intTyOp0) { continue; }
|
||||
unsigned bitw = intTyOp0->getBitWidth();
|
||||
IntegerType *IntType = IntegerType::get(C, bitw);
|
||||
|
||||
@ -555,6 +556,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_ONE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UNE ||
|
||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UGT ||
|
||||
@ -605,10 +607,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
: sizeInBits == 64 ? 53
|
||||
: sizeInBits == 128 ? 113
|
||||
: sizeInBits == 16 ? 11
|
||||
/* sizeInBits == 80 */
|
||||
: 65;
|
||||
: sizeInBits == 80 ? 65
|
||||
: sizeInBits - 8;
|
||||
|
||||
const unsigned shiftR_exponent = precision - 1;
|
||||
const unsigned shiftR_exponent = precision - 1;
|
||||
// BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit
|
||||
const unsigned long long mask_fraction =
|
||||
(1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1);
|
||||
const unsigned long long mask_exponent =
|
||||
@ -735,6 +738,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
BasicBlock * signequal2_bb = signequal_bb;
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_UEQ:
|
||||
case CmpInst::FCMP_OEQ:
|
||||
icmp_exponent_result =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
|
||||
@ -816,6 +820,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_UEQ:
|
||||
case CmpInst::FCMP_OEQ:
|
||||
/* if the exponents are satifying the compare do a fraction cmp in
|
||||
* middle_bb */
|
||||
@ -900,11 +905,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
/* compare the fractions of the operands */
|
||||
Instruction *icmp_fraction_result;
|
||||
Instruction *icmp_fraction_result2;
|
||||
BasicBlock * middle2_bb = middle_bb;
|
||||
PHINode * PN2 = nullptr;
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_UEQ:
|
||||
case CmpInst::FCMP_OEQ:
|
||||
icmp_fraction_result =
|
||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
|
||||
@ -927,6 +932,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
case CmpInst::FCMP_OLT:
|
||||
case CmpInst::FCMP_ULT: {
|
||||
|
||||
Instruction *icmp_fraction_result2;
|
||||
|
||||
middle2_bb = middle_bb->splitBasicBlock(
|
||||
BasicBlock::iterator(middle_bb->getTerminator()));
|
||||
|
||||
@ -980,6 +987,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
switch (FcmpInst->getPredicate()) {
|
||||
|
||||
case CmpInst::FCMP_UEQ:
|
||||
case CmpInst::FCMP_OEQ:
|
||||
/* unequal signs cannot be equal values */
|
||||
/* goto false branch */
|
||||
@ -1294,12 +1302,9 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
case 64:
|
||||
count += splitIntCompares(M, bitw);
|
||||
/*
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
||||
count
|
||||
<< " split\n";
|
||||
*/
|
||||
if (debug)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " split\n";
|
||||
bitw >>= 1;
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
||||
@ -1307,12 +1312,9 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
#endif
|
||||
case 32:
|
||||
count += splitIntCompares(M, bitw);
|
||||
/*
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
||||
count
|
||||
<< " split\n";
|
||||
*/
|
||||
if (debug)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " split\n";
|
||||
bitw >>= 1;
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
||||
@ -1320,13 +1322,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
#endif
|
||||
case 16:
|
||||
count += splitIntCompares(M, bitw);
|
||||
/*
|
||||
if (!be_quiet)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
||||
count
|
||||
<< " split\n";
|
||||
*/
|
||||
bitw >>= 1;
|
||||
if (debug)
|
||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||
<< " split\n";
|
||||
// bitw >>= 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1 +1 @@
|
||||
d66c9e2654
|
||||
e36a30ebca
|
||||
|
@ -17,7 +17,7 @@ The idea and much of the initial implementation comes from Andrew Griffiths.
|
||||
The actual implementation on current QEMU (shipped as qemuafl) is from
|
||||
Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining.
|
||||
|
||||
## 2) How to use
|
||||
## 2) How to use qemu_mode
|
||||
|
||||
The feature is implemented with a patched QEMU. The simplest way
|
||||
to build it is to run ./build_qemu_support.sh. The script will download,
|
||||
@ -176,7 +176,12 @@ Comparative measurements of execution speed or instrumentation coverage will be
|
||||
fairly meaningless if the optimization levels or instrumentation scopes don't
|
||||
match.
|
||||
|
||||
## 12) Gotchas, feedback, bugs
|
||||
## 12) Other features
|
||||
|
||||
With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered signal
|
||||
handlers of the target.
|
||||
|
||||
## 13) Gotchas, feedback, bugs
|
||||
|
||||
If you need to fix up checksums or do other cleanup on mutated test cases, see
|
||||
utils/custom_mutators/ for a viable solution.
|
||||
@ -197,19 +202,12 @@ with -march=core2, can help.
|
||||
Beyond that, this is an early-stage mechanism, so fields reports are welcome.
|
||||
You can send them to <afl-users@googlegroups.com>.
|
||||
|
||||
## 13) Alternatives: static rewriting
|
||||
## 14) Alternatives: static rewriting
|
||||
|
||||
Statically rewriting binaries just once, instead of attempting to translate
|
||||
them at run time, can be a faster alternative. That said, static rewriting is
|
||||
fraught with peril, because it depends on being able to properly and fully model
|
||||
program control flow without actually executing each and every code path.
|
||||
|
||||
The best implementation is this one:
|
||||
|
||||
https://github.com/vanhauser-thc/afl-dyninst
|
||||
|
||||
The issue however is Dyninst which is not rewriting the binaries so that
|
||||
they run stable. A lot of crashes happen, especially in C++ programs that
|
||||
use throw/catch. Try it first, and if it works for you be happy as it is
|
||||
2-3x as fast as qemu_mode, however usually not as fast as QEMU persistent mode.
|
||||
|
||||
Checkout the "Fuzzing binary-only targets" section in our main README.md and
|
||||
the docs/binaryonly_fuzzing.md document for more information and hints.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user