mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-29 08:22:46 +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, _ = p.communicate()
|
||||||
o = str(o, "utf-8")
|
o = str(o, "utf-8")
|
||||||
o = re.sub(r".*ersion ", "", o)
|
o = re.sub(r".*ersion ", "", o)
|
||||||
#o = o[len("clang-format version "):].strip()
|
# o = o[len("clang-format version "):].strip()
|
||||||
o = o[:o.find(".")]
|
o = o[: o.find(".")]
|
||||||
o = int(o)
|
o = int(o)
|
||||||
except:
|
except:
|
||||||
print ("clang-format-11 is needed. Aborted.")
|
print("clang-format-11 is needed. Aborted.")
|
||||||
exit(1)
|
exit(1)
|
||||||
#if o < 7:
|
# if o < 7:
|
||||||
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
||||||
# CLANG_FORMAT_BIN = 'clang-format-7'
|
# CLANG_FORMAT_BIN = 'clang-format-7'
|
||||||
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
|
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
|
||||||
@ -52,7 +52,7 @@ if CLANG_FORMAT_BIN is None:
|
|||||||
# print ("clang-format 7 or above is needed. Aborted.")
|
# print ("clang-format 7 or above is needed. Aborted.")
|
||||||
# exit(1)
|
# exit(1)
|
||||||
else:
|
else:
|
||||||
CLANG_FORMAT_BIN = 'clang-format-11'
|
CLANG_FORMAT_BIN = "clang-format-11"
|
||||||
|
|
||||||
COLUMN_LIMIT = 80
|
COLUMN_LIMIT = 80
|
||||||
for line in fmt.split("\n"):
|
for line in fmt.split("\n"):
|
||||||
@ -72,23 +72,44 @@ def custom_format(filename):
|
|||||||
|
|
||||||
for line in src.split("\n"):
|
for line in src.split("\n"):
|
||||||
if line.lstrip().startswith("#"):
|
if line.lstrip().startswith("#"):
|
||||||
if line[line.find("#")+1:].lstrip().startswith("define"):
|
if line[line.find("#") + 1 :].lstrip().startswith("define"):
|
||||||
in_define = True
|
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("/*")
|
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
|
define_padding = 0
|
||||||
if last_line is not None and in_define and last_line.endswith("\\"):
|
if last_line is not None and in_define and last_line.endswith("\\"):
|
||||||
last_line = last_line[:-1]
|
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
|
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
|
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
|
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||||
|
|
||||||
if not line.endswith("\\"):
|
if not line.endswith("\\"):
|
||||||
@ -97,14 +118,15 @@ def custom_format(filename):
|
|||||||
out += line + "\n"
|
out += line + "\n"
|
||||||
last_line = line
|
last_line = line
|
||||||
|
|
||||||
return (out)
|
return out
|
||||||
|
|
||||||
|
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
print ("Usage: ./format.py [-i] <filename>")
|
print("Usage: ./format.py [-i] <filename>")
|
||||||
print ()
|
print()
|
||||||
print (" The -i option, if specified, let the script to modify in-place")
|
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(" the source files. By default the results are written to stdout.")
|
||||||
print()
|
print()
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
@ -120,4 +142,3 @@ for filename in args:
|
|||||||
f.write(code)
|
f.write(code)
|
||||||
else:
|
else:
|
||||||
print(code)
|
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
|
libAFLDriver.a
|
||||||
libAFLQemuDriver.a
|
libAFLQemuDriver.a
|
||||||
test/.afl_performance
|
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 {
|
cc_defaults {
|
||||||
name: "afl-defaults",
|
name: "afl-defaults",
|
||||||
|
sanitize: {
|
||||||
|
never: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
local_include_dirs: [
|
||||||
|
"include",
|
||||||
|
"instrumentation",
|
||||||
|
],
|
||||||
|
|
||||||
cflags: [
|
cflags: [
|
||||||
|
"-flto=full",
|
||||||
"-funroll-loops",
|
"-funroll-loops",
|
||||||
"-Wno-pointer-sign",
|
"-Wno-pointer-sign",
|
||||||
"-Wno-pointer-arith",
|
"-Wno-pointer-arith",
|
||||||
@ -10,24 +19,35 @@ cc_defaults {
|
|||||||
"-Wno-unused-function",
|
"-Wno-unused-function",
|
||||||
"-Wno-format",
|
"-Wno-format",
|
||||||
"-Wno-user-defined-warnings",
|
"-Wno-user-defined-warnings",
|
||||||
"-DUSE_TRACE_PC=1",
|
"-DAFL_LLVM_USE_TRACE_PC=1",
|
||||||
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
|
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
|
||||||
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
|
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
|
||||||
"-D__USE_GNU",
|
"-D__USE_GNU",
|
||||||
|
"-D__aarch64__",
|
||||||
|
"-DDEBUG_BUILD",
|
||||||
|
"-U_FORTIFY_SOURCE",
|
||||||
|
"-ggdb3",
|
||||||
|
"-g",
|
||||||
|
"-O0",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_binary {
|
cc_binary {
|
||||||
name: "afl-fuzz",
|
name: "afl-fuzz",
|
||||||
static_executable: true,
|
|
||||||
host_supported: true,
|
host_supported: true,
|
||||||
|
compile_multilib: "64",
|
||||||
|
|
||||||
defaults: [
|
defaults: [
|
||||||
"afl-defaults",
|
"afl-defaults",
|
||||||
],
|
],
|
||||||
|
|
||||||
srcs: [
|
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: [
|
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: [
|
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: [
|
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: [
|
srcs: [
|
||||||
"afl-gotcpu.c",
|
"src/afl-gotcpu.c",
|
||||||
|
"src/afl-common.c",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_binary_host {
|
cc_binary_host {
|
||||||
name: "afl-clang-fast",
|
name: "afl-cc",
|
||||||
static_executable: true,
|
static_executable: true,
|
||||||
|
|
||||||
defaults: [
|
defaults: [
|
||||||
@ -98,44 +130,144 @@ cc_binary_host {
|
|||||||
cflags: [
|
cflags: [
|
||||||
"-D__ANDROID__",
|
"-D__ANDROID__",
|
||||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
"-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: [
|
srcs: [
|
||||||
"src/afl-cc.c",
|
"src/afl-cc.c",
|
||||||
],
|
"src/afl-common.c",
|
||||||
}
|
|
||||||
|
|
||||||
cc_binary_host {
|
|
||||||
name: "afl-clang-fast++",
|
|
||||||
static_executable: true,
|
|
||||||
|
|
||||||
defaults: [
|
|
||||||
"afl-defaults",
|
|
||||||
],
|
],
|
||||||
|
|
||||||
cflags: [
|
symlinks: [
|
||||||
"-D__ANDROID__",
|
"afl-clang-fast",
|
||||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
"afl-clang-fast++",
|
||||||
],
|
|
||||||
|
|
||||||
srcs: [
|
|
||||||
"src/afl-cc.c",
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_library_static {
|
cc_library_static {
|
||||||
name: "afl-llvm-rt",
|
name: "afl-llvm-rt",
|
||||||
compile_multilib: "both",
|
compile_multilib: "64",
|
||||||
vendor_available: true,
|
vendor_available: true,
|
||||||
host_supported: true,
|
host_supported: true,
|
||||||
recovery_available: true,
|
recovery_available: true,
|
||||||
sdk_version: "9",
|
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: [
|
defaults: [
|
||||||
"afl-defaults",
|
"afl-defaults",
|
||||||
],
|
],
|
||||||
|
|
||||||
srcs: [
|
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
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
env NO_ARCH_OPT 1
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||||
automake \
|
automake \
|
||||||
|
ninja-build \
|
||||||
bison flex \
|
bison flex \
|
||||||
build-essential \
|
build-essential \
|
||||||
git \
|
git \
|
||||||
python3 python3-dev python3-setuptools python-is-python3 \
|
python3 python3-dev python3-setuptools python-is-python3 \
|
||||||
libtool libtool-bin \
|
libtool libtool-bin \
|
||||||
libglib2.0-dev \
|
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 \
|
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||||
libpixman-1-dev \
|
libpixman-1-dev \
|
||||||
gnuplot-nox \
|
gnuplot-nox \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& 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 -
|
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 && \
|
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 && \
|
RUN apt-get update && apt-get full-upgrade -y && \
|
||||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||||
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gdb lcov \
|
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gdb lcov \
|
||||||
clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
|
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||||
libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \
|
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||||
libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \
|
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||||
liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \
|
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||||
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools \
|
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& 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/gcc gcc /usr/bin/gcc-10 0
|
||||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-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_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 ..
|
RUN cd /afl-cov && make install && cd ..
|
||||||
|
|
||||||
COPY . /AFLplusplus
|
COPY . /AFLplusplus
|
||||||
WORKDIR /AFLplusplus
|
WORKDIR /AFLplusplus
|
||||||
|
|
||||||
RUN export REAL_CXX=g++-10 && export CC=gcc-10 && \
|
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
|
||||||
export CXX=g++-10 && make clean && \
|
|
||||||
make distrib && make install && make clean
|
make distrib && make install && make clean
|
||||||
|
|
||||||
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
|
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
|
||||||
|
74
GNUmakefile
74
GNUmakefile
@ -42,8 +42,8 @@ endif
|
|||||||
|
|
||||||
ifdef ASAN_BUILD
|
ifdef ASAN_BUILD
|
||||||
$(info Compiling ASAN version of binaries)
|
$(info Compiling ASAN version of binaries)
|
||||||
override CFLAGS+=$(ASAN_CFLAGS)
|
override CFLAGS += $(ASAN_CFLAGS)
|
||||||
LDFLAGS+=$(ASAN_LDFLAGS)
|
LDFLAGS += $(ASAN_LDFLAGS)
|
||||||
endif
|
endif
|
||||||
ifdef UBSAN_BUILD
|
ifdef UBSAN_BUILD
|
||||||
$(info Compiling UBSAN version of binaries)
|
$(info Compiling UBSAN version of binaries)
|
||||||
@ -57,8 +57,6 @@ ifdef MSAN_BUILD
|
|||||||
override LDFLAGS += -fsanitize=memory
|
override LDFLAGS += -fsanitize=memory
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
CFLAGS_FLTO ?= -flto=full
|
CFLAGS_FLTO ?= -flto=full
|
||||||
@ -77,13 +75,17 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -
|
|||||||
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||||
endif
|
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"
|
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"
|
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||||
ifndef SOURCE_DATE_EPOCH
|
# SPECIAL_PERFORMANCE += -march=native
|
||||||
#CFLAGS_OPT += -march=native
|
#endif
|
||||||
SPECIAL_PERFORMANCE += -march=native
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
# OS X does not like _FORTIFY_SOURCE=2
|
# OS X does not like _FORTIFY_SOURCE=2
|
||||||
ifndef DEBUG
|
ifndef DEBUG
|
||||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||||
@ -92,15 +94,15 @@ endif
|
|||||||
|
|
||||||
ifeq "$(shell uname)" "SunOS"
|
ifeq "$(shell uname)" "SunOS"
|
||||||
CFLAGS_OPT += -Wno-format-truncation
|
CFLAGS_OPT += -Wno-format-truncation
|
||||||
LDFLAGS=-lkstat -lrt
|
LDFLAGS = -lkstat -lrt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef STATIC
|
ifdef STATIC
|
||||||
$(info Compiling static version of binaries, disabling python though)
|
$(info Compiling static version of binaries, disabling python though)
|
||||||
# Disable python for static compilation to simplify things
|
# Disable python for static compilation to simplify things
|
||||||
PYTHON_OK=0
|
PYTHON_OK = 0
|
||||||
PYFLAGS=
|
PYFLAGS=
|
||||||
PYTHON_INCLUDE=/
|
PYTHON_INCLUDE = /
|
||||||
|
|
||||||
CFLAGS_OPT += -static
|
CFLAGS_OPT += -static
|
||||||
LDFLAGS += -lm -lpthread -lz -lutil
|
LDFLAGS += -lm -lpthread -lz -lutil
|
||||||
@ -117,6 +119,7 @@ ifdef INTROSPECTION
|
|||||||
CFLAGS_OPT += -DINTROSPECTION=1
|
CFLAGS_OPT += -DINTROSPECTION=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
ifneq "$(shell uname -m)" "x86_64"
|
ifneq "$(shell uname -m)" "x86_64"
|
||||||
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
|
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
|
||||||
ifneq "$(shell uname -m)" "amd64"
|
ifneq "$(shell uname -m)" "amd64"
|
||||||
@ -302,7 +305,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
|
|||||||
|
|
||||||
.PHONY: llvm
|
.PHONY: llvm
|
||||||
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; }
|
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||||
|
|
||||||
.PHONY: gcc_plugin
|
.PHONY: gcc_plugin
|
||||||
@ -361,6 +364,7 @@ help:
|
|||||||
@echo NO_PYTHON - disable python support
|
@echo NO_PYTHON - disable python support
|
||||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
@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 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 "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
|
||||||
@echo "=========================================="
|
@echo "=========================================="
|
||||||
@echo e.g.: make ASAN_BUILD=1
|
@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
|
@ln -sf afl-as as
|
||||||
|
|
||||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
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
|
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -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
|
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
|
$(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
|
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 -o $@ $(LDFLAGS)
|
$(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
|
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) 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/*.c
|
||||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
./.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 *.h
|
||||||
./.custom-format.py -i *.c
|
./.custom-format.py -i *.c
|
||||||
|
|
||||||
@ -512,23 +518,23 @@ code-format:
|
|||||||
ifndef AFL_NO_X86
|
ifndef AFL_NO_X86
|
||||||
test_build: afl-cc afl-gcc afl-as afl-showmap
|
test_build: afl-cc afl-gcc afl-as afl-showmap
|
||||||
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
|
@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
|
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
|
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||||
@rm -f 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
|
@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
|
||||||
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
|
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
|
||||||
@echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
|
# @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 )
|
# @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
|
# 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
|
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||||
@rm -f 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!"; \
|
# @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." ) || \
|
# 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 "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
|
||||||
@echo
|
# @echo
|
||||||
@echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
|
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
|
||||||
else
|
else
|
||||||
test_build: afl-cc afl-as afl-showmap
|
test_build: afl-cc afl-as afl-showmap
|
||||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
@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 utils/argv_fuzzing clean
|
||||||
$(MAKE) -C qemu_mode/unsigaction clean
|
$(MAKE) -C qemu_mode/unsigaction clean
|
||||||
$(MAKE) -C qemu_mode/libcompcov clean
|
$(MAKE) -C qemu_mode/libcompcov clean
|
||||||
|
$(MAKE) -C qemu_mode/libqasan clean
|
||||||
ifeq "$(IN_REPO)" "1"
|
ifeq "$(IN_REPO)" "1"
|
||||||
test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
|
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
|
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||||
@ -574,11 +581,11 @@ deepclean: clean
|
|||||||
|
|
||||||
.PHONY: distrib
|
.PHONY: distrib
|
||||||
distrib: all
|
distrib: all
|
||||||
-$(MAKE) -f GNUmakefile.llvm
|
-$(MAKE) -j -f GNUmakefile.llvm
|
||||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||||
$(MAKE) -C utils/libdislocator
|
$(MAKE) -C utils/libdislocator
|
||||||
$(MAKE) -C utils/libtokencap
|
$(MAKE) -C utils/libtokencap
|
||||||
$(MAKE) -C utils/aflpp_driver
|
-$(MAKE) -C utils/aflpp_driver
|
||||||
$(MAKE) -C utils/afl_network_proxy
|
$(MAKE) -C utils/afl_network_proxy
|
||||||
$(MAKE) -C utils/socket_fuzzing
|
$(MAKE) -C utils/socket_fuzzing
|
||||||
$(MAKE) -C utils/argv_fuzzing
|
$(MAKE) -C utils/argv_fuzzing
|
||||||
@ -586,7 +593,7 @@ distrib: all
|
|||||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||||
|
|
||||||
.PHONY: binary-only
|
.PHONY: binary-only
|
||||||
binary-only: all
|
binary-only: test_shm test_python ready $(PROGS)
|
||||||
$(MAKE) -C utils/libdislocator
|
$(MAKE) -C utils/libdislocator
|
||||||
$(MAKE) -C utils/libtokencap
|
$(MAKE) -C utils/libtokencap
|
||||||
$(MAKE) -C utils/afl_network_proxy
|
$(MAKE) -C utils/afl_network_proxy
|
||||||
@ -597,11 +604,11 @@ binary-only: all
|
|||||||
|
|
||||||
.PHONY: source-only
|
.PHONY: source-only
|
||||||
source-only: all
|
source-only: all
|
||||||
-$(MAKE) -f GNUmakefile.llvm
|
-$(MAKE) -j -f GNUmakefile.llvm
|
||||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||||
$(MAKE) -C utils/libdislocator
|
$(MAKE) -C utils/libdislocator
|
||||||
$(MAKE) -C utils/libtokencap
|
$(MAKE) -C utils/libtokencap
|
||||||
$(MAKE) -C utils/aflpp_driver
|
-$(MAKE) -C utils/aflpp_driver
|
||||||
|
|
||||||
%.8: %
|
%.8: %
|
||||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
@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 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 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 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 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 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
|
@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
|
.PHONY: test_build
|
||||||
test_build: $(PROGS)
|
test_build: $(PROGS)
|
||||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
@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
|
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
|
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||||
@rm -f 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//' )
|
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_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_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_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_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 )
|
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
|
endif
|
||||||
|
|
||||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
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
|
endif
|
||||||
|
|
||||||
LLVM_TOO_OLD=1
|
LLVM_TOO_OLD=1
|
||||||
@ -208,12 +213,12 @@ ifeq "$(LLVM_LTO)" "1"
|
|||||||
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
||||||
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
||||||
else
|
else
|
||||||
$(warn ld.lld not found, cannot enable LTO mode)
|
$(warning ld.lld not found, cannot enable LTO mode)
|
||||||
LLVM_LTO = 0
|
LLVM_LTO = 0
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
else
|
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
|
LLVM_LTO = 0
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@ -226,7 +231,7 @@ ifeq "$(LLVM_LTO)" "1"
|
|||||||
AFL_CLANG_LDPATH=1
|
AFL_CLANG_LDPATH=1
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
$(warn -fuse-ld is not working, cannot enable LTO mode)
|
$(warning -fuse-ld is not working, cannot enable LTO mode)
|
||||||
LLVM_LTO = 0
|
LLVM_LTO = 0
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@ -357,7 +362,7 @@ instrumentation/afl-common.o: ./src/afl-common.c
|
|||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
./afl-cc: src/afl-cc.c instrumentation/afl-common.o
|
./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-c++
|
||||||
@ln -sf afl-cc ./afl-gcc
|
@ln -sf afl-cc ./afl-gcc
|
||||||
@ln -sf afl-cc ./afl-g++
|
@ln -sf afl-cc ./afl-g++
|
||||||
@ -452,7 +457,7 @@ document:
|
|||||||
.PHONY: test_build
|
.PHONY: test_build
|
||||||
test_build: $(PROGS)
|
test_build: $(PROGS)
|
||||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
@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
|
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
|
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||||
@rm -f 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">
|
<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.11a
|
||||||
|
|
||||||
Github Version: 3.00a
|
|
||||||
|
|
||||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||||
|
|
||||||
@ -23,26 +21,33 @@
|
|||||||
mutations, more and better instrumentation, custom module support, etc.
|
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/)
|
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:
|
behaviours and defaults:
|
||||||
|
|
||||||
* There are no llvm_mode and gcc_plugin subdirectories anymore and there is
|
* 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
|
only one compiler: afl-cc. All previous compilers now symlink to this one.
|
||||||
compiler. All instrumentation source code is now in the `instrumentation/`
|
All instrumentation source code is now in the `instrumentation/` folder.
|
||||||
folder.
|
|
||||||
* The gcc_plugin was replaced with a new version submitted by AdaCore that
|
* 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
|
* 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.
|
ninja build tool version and python3 setuptools are required.
|
||||||
qemu_mode also got new options like snapshotting, instrumenting specific
|
qemu_mode also got new options like snapshotting, instrumenting specific
|
||||||
shared libraries, etc. Additionally QEMU 5.1 supports more CPU targets so
|
shared libraries, etc. Additionally QEMU 5.1 supports more CPU targets so
|
||||||
this is really worth it.
|
this is really worth it.
|
||||||
* When instrumenting targets, afl-cc will not supersede optimizations. This
|
* When instrumenting targets, afl-cc will not supersede optimizations anymore
|
||||||
allows to fuzz targets as same as they are built for debug or release.
|
if any were given. This allows to fuzz targets as same as they are built
|
||||||
|
for debug or release.
|
||||||
* afl-fuzz:
|
* afl-fuzz:
|
||||||
* if neither -M or -S is specified, `-S default` is assumed, so more
|
* if neither -M or -S is specified, `-S default` is assumed, so more
|
||||||
fuzzers can easily be added later
|
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
|
* 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
|
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).
|
`AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500 (default: 50).
|
||||||
|
* -M mains do not perform trimming
|
||||||
* examples/ got renamed to utils/
|
* examples/ got renamed to utils/
|
||||||
* libtokencap/ libdislocator/ and qdbi_mode/ were moved 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
|
* 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)
|
3. [How to fuzz a target](#how-to-fuzz-with-afl)
|
||||||
4. [Fuzzing binary-only targets](#fuzzing-binary-only-targets)
|
4. [Fuzzing binary-only targets](#fuzzing-binary-only-targets)
|
||||||
5. [Good examples and writeups of afl++ usages](#good-examples-and-writeups)
|
5. [Good examples and writeups of afl++ usages](#good-examples-and-writeups)
|
||||||
6. [Branches](#branches)
|
6. [CI Fuzzing](#ci-fuzzing)
|
||||||
7. [Want to help?](#help-wanted)
|
7. [Branches](#branches)
|
||||||
8. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
|
8. [Want to help?](#help-wanted)
|
||||||
|
9. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
|
||||||
|
|
||||||
## Important features of afl++
|
## Important features of afl++
|
||||||
|
|
||||||
@ -88,7 +95,7 @@ behaviours and defaults:
|
|||||||
| Ngram prev_loc Coverage | | x(6) | | | |
|
| Ngram prev_loc Coverage | | x(6) | | | |
|
||||||
| Context Coverage | | x(6) | | | |
|
| Context Coverage | | x(6) | | | |
|
||||||
| Auto Dictionary | | x(7) | | | |
|
| 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
|
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
|
||||||
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
|
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
|
||||||
@ -97,6 +104,7 @@ behaviours and defaults:
|
|||||||
5. upcoming, development in the branch
|
5. upcoming, development in the branch
|
||||||
6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
|
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`
|
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:
|
Among others, the following features and patches have been integrated:
|
||||||
|
|
||||||
@ -139,9 +147,6 @@ behaviours and defaults:
|
|||||||
|
|
||||||
## Help wanted
|
## 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.
|
We have several ideas we would like to see in AFL++ to make it even better.
|
||||||
However, we already work on so many things that we do not have the time for
|
However, we already work on so many things that we do not have the time for
|
||||||
all the big ideas.
|
all the big ideas.
|
||||||
@ -206,7 +211,7 @@ These build targets exist:
|
|||||||
afl++ binaries by passing the STATIC=1 argument to make:
|
afl++ binaries by passing the STATIC=1 argument to make:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
make all STATIC=1
|
make STATIC=1
|
||||||
```
|
```
|
||||||
|
|
||||||
These build options exist:
|
These build options exist:
|
||||||
@ -219,6 +224,7 @@ These build options exist:
|
|||||||
* NO_PYTHON - disable python support
|
* NO_PYTHON - disable python support
|
||||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
* 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)
|
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
|
||||||
|
|
||||||
e.g.: make ASAN_BUILD=1
|
e.g.: make ASAN_BUILD=1
|
||||||
@ -283,9 +289,9 @@ anything below 9 is not recommended.
|
|||||||
|
|
|
|
||||||
v
|
v
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| if you want to instrument only | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
|
| gcc 5+ is available | -> 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
|
+--------------------------------+ see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
|
||||||
+--------------------------------+ [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
[instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
||||||
|
|
|
|
||||||
| if not, or if you do not have a gcc with plugin support
|
| 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)
|
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
|
||||||
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
|
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
|
||||||
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.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:
|
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
|
1. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||||
2. 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-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++,
|
||||||
afl-gcc-fast, afl-g++-fast
|
afl-gcc-fast, afl-g++-fast (recommended!)
|
||||||
3. using the environment variable AFL_CC_COMPILER with MODE
|
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
|
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
|
Because no afl specific command-line options are accepted (beside the
|
||||||
--afl-MODE command), the compile-time tools make fairly broad use of environment
|
--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)
|
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)
|
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:
|
are interested in:
|
||||||
|
|
||||||
* To instrument only those 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
|
create a file with all the filenames of the source code that should be
|
||||||
instrumented.
|
instrumented.
|
||||||
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if either the clang
|
For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if a mode other than
|
||||||
version is below 7 or the CLASSIC instrumentation is used - just put one
|
DEFAULT/PCGUARD is used or you have llvm > 10.0.0 - just put one
|
||||||
filename or function per line (no directory information necessary for
|
filename or function per line (no directory information necessary for
|
||||||
filenames9, and either set `export AFL_LLVM_ALLOWLIST=allowlist.txt` **or**
|
filenames9, and either set `export AFL_LLVM_ALLOWLIST=allowlist.txt` **or**
|
||||||
`export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per
|
`export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per
|
||||||
@ -353,10 +359,6 @@ are interested in:
|
|||||||
unless requested (ALLOWLIST).
|
unless requested (ALLOWLIST).
|
||||||
**NOTE:** During optimization functions might be inlined and then would not match!
|
**NOTE:** During optimization functions might be inlined and then would not match!
|
||||||
See [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
|
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
|
There are many more options and modes available however these are most of the
|
||||||
time less effective. See:
|
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
|
If you just use one CPU for fuzzing, then you are fuzzing just for fun and not
|
||||||
seriously :-)
|
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
|
#### a) Running afl-fuzz
|
||||||
|
|
||||||
Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on
|
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:
|
All other secondaries should be used like this:
|
||||||
* A third to a half with the MOpt mutator enabled: `-L 0`
|
* A third to a half with the MOpt mutator enabled: `-L 0`
|
||||||
* run with a different power schedule, available are:
|
* 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`
|
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.
|
You can also use different fuzzers.
|
||||||
If you are using afl spinoffs or afl conforming fuzzers, then just use the
|
If you are using afl spinoffs or afl conforming fuzzers, then just use the
|
||||||
same -o directory and give it a unique `-S` name.
|
same -o directory and give it a unique `-S` name.
|
||||||
Examples are:
|
Examples are:
|
||||||
|
* [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/)
|
||||||
* [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
|
* [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
|
||||||
* [AFLsmart](https://github.com/aflsmart/aflsmart)
|
* [AFLsmart](https://github.com/aflsmart/aflsmart)
|
||||||
* [FairFuzz](https://github.com/carolemieux/afl-rb)
|
* [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)
|
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.
|
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`.
|
directory of a different fuzzer is, e.g. `-F /src/target/honggfuzz`.
|
||||||
|
|
||||||
#### c) The status of the fuzz campaign
|
#### 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)
|
* 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)
|
* 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: 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
|
* 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)
|
* 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++
|
Note that there are also a lot of tools out there that help fuzzing with afl++
|
||||||
(some might be deprecated or unsupported):
|
(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:
|
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.
|
* [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.
|
* [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.
|
* [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.
|
* [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
|
## Fuzzing binary-only targets
|
||||||
|
|
||||||
When source code is *NOT* available, afl++ offers various support for fast,
|
When source code is *NOT* available, afl++ offers various support for fast,
|
||||||
on-the-fly instrumentation of black-box binaries.
|
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
|
### QEMU
|
||||||
|
|
||||||
For linux programs and its libraries this is accomplished with a version of
|
For linux programs and its libraries this is accomplished with a version of
|
||||||
@ -739,7 +789,8 @@ feature by doing:
|
|||||||
cd qemu_mode
|
cd qemu_mode
|
||||||
./build_qemu_support.sh
|
./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).
|
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
|
The mode is approximately 2-5x slower than compile-time instrumentation, and is
|
||||||
less conducive to parallelization.
|
less conducive to parallelization.
|
||||||
@ -747,11 +798,13 @@ less conducive to parallelization.
|
|||||||
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
|
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
|
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).
|
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
|
### Unicorn
|
||||||
|
|
||||||
For non-Linux binaries you can use afl++'s unicorn mode which can emulate
|
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).
|
See [unicorn_mode](unicorn_mode/README.md).
|
||||||
|
|
||||||
It can be easily built by:
|
It can be easily built by:
|
||||||
@ -763,16 +816,16 @@ cd unicorn_mode
|
|||||||
### Shared libraries
|
### Shared libraries
|
||||||
|
|
||||||
If the goal is to fuzz a dynamic library then there are two options available.
|
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)
|
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
|
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
|
### More
|
||||||
|
|
||||||
A more comprehensive description of these and other options can be found in
|
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
|
## Challenges of guided fuzzing
|
||||||
|
|
||||||
@ -1114,7 +1167,7 @@ without feedback, bug reports, or patches from:
|
|||||||
Khaled Yakdan Kuang-che Wu
|
Khaled Yakdan Kuang-che Wu
|
||||||
Josephine Calliotte Konrad Welc
|
Josephine Calliotte Konrad Welc
|
||||||
Thomas Rooijakkers David Carlier
|
Thomas Rooijakkers David Carlier
|
||||||
Ruben ten Hove
|
Ruben ten Hove Joey Jiao
|
||||||
```
|
```
|
||||||
|
|
||||||
Thank you!
|
Thank you!
|
||||||
@ -1122,8 +1175,18 @@ Thank you!
|
|||||||
|
|
||||||
## Cite
|
## 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:
|
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,
|
@inproceedings {AFLplusplus-Woot20,
|
||||||
author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
|
author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
|
||||||
title = {{AFL++}: Combining Incremental Steps of Fuzzing Research},
|
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
|
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||||
- afl-plot to support multiple plot_data
|
- afl-plot to support multiple plot_data
|
||||||
- afl_custom_fuzz_splice_optin()
|
- afl_custom_fuzz_splice_optin()
|
||||||
|
- afl_custom_splice()
|
||||||
- intel-pt tracer
|
- intel-pt tracer
|
||||||
|
|
||||||
## Further down the road
|
## Further down the road
|
||||||
|
|
||||||
afl-fuzz:
|
afl-fuzz:
|
||||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
- 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:
|
qemu_mode:
|
||||||
- non colliding instrumentation
|
- non colliding instrumentation
|
||||||
|
15
afl-cmin
15
afl-cmin
@ -120,6 +120,7 @@ function usage() {
|
|||||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
"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_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_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_PATH: path for the afl-showmap binary if not found anywhere else\n" \
|
||||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
||||||
exit 1
|
exit 1
|
||||||
@ -182,14 +183,12 @@ BEGIN {
|
|||||||
if (_go_c == "Q") {
|
if (_go_c == "Q") {
|
||||||
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
extra_par = extra_par " -Q"
|
extra_par = extra_par " -Q"
|
||||||
if ( !mem_limit_given ) mem_limit = "250"
|
|
||||||
qemu_mode = 1
|
qemu_mode = 1
|
||||||
continue
|
continue
|
||||||
} else
|
} else
|
||||||
if (_go_c == "U") {
|
if (_go_c == "U") {
|
||||||
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
extra_par = extra_par " -U"
|
extra_par = extra_par " -U"
|
||||||
if ( !mem_limit_given ) mem_limit = "250"
|
|
||||||
unicorn_mode = 1
|
unicorn_mode = 1
|
||||||
continue
|
continue
|
||||||
} else
|
} else
|
||||||
@ -199,7 +198,7 @@ BEGIN {
|
|||||||
usage()
|
usage()
|
||||||
} # while options
|
} # while options
|
||||||
|
|
||||||
if (!mem_limit) mem_limit = 200
|
if (!mem_limit) mem_limit = "none"
|
||||||
if (!timeout) timeout = "none"
|
if (!timeout) timeout = "none"
|
||||||
|
|
||||||
# get program args
|
# get program args
|
||||||
@ -344,7 +343,7 @@ BEGIN {
|
|||||||
stat_format = "-f '%z %N'" # *BSD, MacOS
|
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 = "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) {
|
while (cmdline | getline) {
|
||||||
sub(/^[0-9]+ (\.\/)?/,"",$0)
|
sub(/^[0-9]+ (\.\/)?/,"",$0)
|
||||||
infilesSmallToBig[i++] = $0
|
infilesSmallToBig[i++] = $0
|
||||||
@ -356,7 +355,7 @@ BEGIN {
|
|||||||
# Make sure that we're not dealing with a directory.
|
# Make sure that we're not dealing with a directory.
|
||||||
|
|
||||||
if (0 == system("test -d "in_dir"/"first_file)) {
|
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
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +365,7 @@ BEGIN {
|
|||||||
cp_tool = "cp"
|
cp_tool = "cp"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) {
|
||||||
# Make sure that we can actually get anything out of afl-showmap before we
|
# Make sure that we can actually get anything out of afl-showmap before we
|
||||||
# waste too much time.
|
# waste too much time.
|
||||||
|
|
||||||
@ -394,6 +394,7 @@ BEGIN {
|
|||||||
}
|
}
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Let's roll!
|
# 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)
|
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 {
|
} else {
|
||||||
print " Processing "in_count" files (forkserver mode)..."
|
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"
|
# 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"\" -- \""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) {
|
if (retval && !AFL_CMIN_CRASHES_ONLY) {
|
||||||
|
@ -45,7 +45,7 @@ echo
|
|||||||
|
|
||||||
# Process command-line options...
|
# Process command-line options...
|
||||||
|
|
||||||
MEM_LIMIT=200
|
MEM_LIMIT=none
|
||||||
TIMEOUT=none
|
TIMEOUT=none
|
||||||
|
|
||||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
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")
|
"Q")
|
||||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
|
||||||
QEMU_MODE=1
|
QEMU_MODE=1
|
||||||
;;
|
;;
|
||||||
"U")
|
"U")
|
||||||
EXTRA_PAR="$EXTRA_PAR -U"
|
EXTRA_PAR="$EXTRA_PAR -U"
|
||||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
|
||||||
UNICORN_MODE=1
|
UNICORN_MODE=1
|
||||||
;;
|
;;
|
||||||
"?")
|
"?")
|
||||||
|
11
afl-plot
11
afl-plot
@ -99,7 +99,7 @@ if [ ! -d "$outputdir" ]; then
|
|||||||
|
|
||||||
fi
|
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
|
mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
|
||||||
|
|
||||||
echo "[*] Generating plots..."
|
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, \\
|
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;
|
'$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_
|
_EOF_
|
||||||
|
|
||||||
) | gnuplot
|
) | gnuplot
|
||||||
@ -172,6 +178,7 @@ cat >"$outputdir/index.html" <<_EOF_
|
|||||||
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
|
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
|
<img src="edges.png" width=1000 height=300>
|
||||||
<img src="high_freq.png" width=1000 height=300><p>
|
<img src="high_freq.png" width=1000 height=300><p>
|
||||||
<img src="low_freq.png" width=1000 height=200><p>
|
<img src="low_freq.png" width=1000 height=200><p>
|
||||||
<img src="exec_speed.png" width=1000 height=200>
|
<img src="exec_speed.png" width=1000 height=200>
|
||||||
@ -183,7 +190,7 @@ _EOF_
|
|||||||
# sensitive, this seems like a reasonable trade-off.
|
# sensitive, this seems like a reasonable trade-off.
|
||||||
|
|
||||||
chmod 755 "$outputdir"
|
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!"
|
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/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/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/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
|
} > /dev/null
|
||||||
echo Settings applied.
|
echo Settings applied.
|
||||||
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
||||||
@ -48,6 +49,12 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then
|
|||||||
sysctl kern.elf64.aslr.enable=0
|
sysctl kern.elf64.aslr.enable=0
|
||||||
} > /dev/null
|
} > /dev/null
|
||||||
echo Settings applied.
|
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 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 ' sysctl hw.ibrs_disable=1'
|
||||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
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.'
|
echo 'System security features cannot be disabled on OpenBSD.'
|
||||||
DONE=1
|
DONE=1
|
||||||
fi
|
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
|
if [ "$PLATFORM" = "NetBSD" ] ; then
|
||||||
{
|
{
|
||||||
#echo It is recommended to enable unprivileged users to set cpu affinity
|
#echo It is recommended to enable unprivileged users to set cpu affinity
|
||||||
@ -79,4 +97,14 @@ if [ "$PLATFORM" = "Darwin" ] ; then
|
|||||||
fi
|
fi
|
||||||
DONE=1
|
DONE=1
|
||||||
fi
|
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
|
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)
|
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"]:
|
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:
|
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"):
|
if os.getenv("WINECOV_QEMU_PATH"):
|
||||||
qemu_path = 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"
|
#include "libhfcommon/util.h"
|
||||||
|
|
||||||
#define PROG_NAME "honggfuzz"
|
#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 */
|
/* Name of the template which will be replaced with the proper name of the file */
|
||||||
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||||
@ -208,6 +208,7 @@ typedef struct {
|
|||||||
const char* crashDir;
|
const char* crashDir;
|
||||||
const char* covDirNew;
|
const char* covDirNew;
|
||||||
bool saveUnique;
|
bool saveUnique;
|
||||||
|
bool saveSmaller;
|
||||||
size_t dynfileqMaxSz;
|
size_t dynfileqMaxSz;
|
||||||
size_t dynfileqCnt;
|
size_t dynfileqCnt;
|
||||||
dynfile_t* dynfileqCurrent;
|
dynfile_t* dynfileqCurrent;
|
||||||
@ -279,9 +280,9 @@ typedef struct {
|
|||||||
cmpfeedback_t* cmpFeedbackMap;
|
cmpfeedback_t* cmpFeedbackMap;
|
||||||
int cmpFeedbackFd;
|
int cmpFeedbackFd;
|
||||||
bool cmpFeedback;
|
bool cmpFeedback;
|
||||||
const char* blacklistFile;
|
const char* blocklistFile;
|
||||||
uint64_t* blacklist;
|
uint64_t* blocklist;
|
||||||
size_t blacklistCnt;
|
size_t blocklistCnt;
|
||||||
bool skipFeedbackOnTimeout;
|
bool skipFeedbackOnTimeout;
|
||||||
uint64_t maxCov[4];
|
uint64_t maxCov[4];
|
||||||
dynFileMethod_t dynFileMethod;
|
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 uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||||
|
|
||||||
static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
|
static inline const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) {
|
||||||
*buf = queue_input;
|
*len = queue_input_size;
|
||||||
run->dynfile->data = queue_input;
|
run->dynfile->data = queue_input;
|
||||||
run->dynfile->size = queue_input_size;
|
run->dynfile->size = queue_input_size;
|
||||||
return queue_input_size;
|
return queue_input;
|
||||||
}
|
}
|
||||||
static inline void input_setSize(run_t* run, size_t sz) {
|
static inline void input_setSize(run_t* run, size_t sz) {
|
||||||
run->dynfile->size = 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
|
@ -39,74 +39,58 @@
|
|||||||
#include "libhfcommon/log.h"
|
#include "libhfcommon/log.h"
|
||||||
#include "libhfcommon/util.h"
|
#include "libhfcommon/util.h"
|
||||||
|
|
||||||
static inline size_t mangle_LenLeft(run_t *run, size_t off) {
|
static inline size_t mangle_LenLeft(run_t* run, size_t off) {
|
||||||
|
|
||||||
if (off >= run->dynfile->size) {
|
if (off >= run->dynfile->size) {
|
||||||
|
|
||||||
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
|
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (run->dynfile->size - off - 1);
|
return (run->dynfile->size - off - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a random value <1:max>, but prefer smaller ones - up to 4KiB */
|
/*
|
||||||
|
* Get a random value <1:max>, but prefer smaller ones
|
||||||
|
* Based on an idea by https://twitter.com/gamozolabs
|
||||||
|
*/
|
||||||
static inline size_t mangle_getLen(size_t max) {
|
static inline size_t mangle_getLen(size_t max) {
|
||||||
|
|
||||||
if (max > _HF_INPUT_MAX_SIZE) {
|
if (max > _HF_INPUT_MAX_SIZE) {
|
||||||
|
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
|
||||||
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max,
|
}
|
||||||
(size_t)_HF_INPUT_MAX_SIZE);
|
if (max == 0) {
|
||||||
|
LOG_F("max == 0");
|
||||||
|
}
|
||||||
|
if (max == 1) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max == 0) { LOG_F("max == 0"); }
|
|
||||||
if (max == 1) { return 1; }
|
|
||||||
|
|
||||||
/* Give 50% chance the the uniform distribution */
|
/* Give 50% chance the the uniform distribution */
|
||||||
switch (util_rndGet(0, 9)) {
|
if (util_rnd64() & 1) {
|
||||||
|
return (size_t)util_rndGet(1, max);
|
||||||
case 0:
|
|
||||||
return (size_t)util_rndGet(1, HF_MIN(16, max));
|
|
||||||
case 1:
|
|
||||||
return (size_t)util_rndGet(1, HF_MIN(64, max));
|
|
||||||
case 2:
|
|
||||||
return (size_t)util_rndGet(1, HF_MIN(256, max));
|
|
||||||
case 3:
|
|
||||||
return (size_t)util_rndGet(1, HF_MIN(1024, max));
|
|
||||||
case 4:
|
|
||||||
return (size_t)util_rndGet(1, HF_MIN(4096, max));
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (size_t)util_rndGet(1, max);
|
/* effectively exprand() */
|
||||||
|
return (size_t)util_rndGet(1, util_rndGet(1, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prefer smaller values here, so use mangle_getLen() */
|
/* Prefer smaller values here, so use mangle_getLen() */
|
||||||
static inline size_t mangle_getOffSet(run_t *run) {
|
static inline size_t mangle_getOffSet(run_t* run) {
|
||||||
|
|
||||||
return mangle_getLen(run->dynfile->size) - 1;
|
return mangle_getLen(run->dynfile->size) - 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Offset which can be equal to the file size */
|
/* Offset which can be equal to the file size */
|
||||||
static inline size_t mangle_getOffSetPlus1(run_t *run) {
|
static inline size_t mangle_getOffSetPlus1(run_t* run) {
|
||||||
|
|
||||||
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
|
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
|
||||||
return mangle_getLen(reqlen) - 1;
|
return mangle_getLen(reqlen) - 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
|
static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
|
||||||
size_t len) {
|
if (off_from >= run->dynfile->size) {
|
||||||
|
return;
|
||||||
if (off_from >= run->dynfile->size) { return; }
|
}
|
||||||
if (off_to >= run->dynfile->size) { return; }
|
if (off_to >= run->dynfile->size) {
|
||||||
if (off_from == off_to) { return; }
|
return;
|
||||||
|
}
|
||||||
|
if (off_from == off_to) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t len_from = run->dynfile->size - off_from;
|
size_t len_from = run->dynfile->size - off_from;
|
||||||
len = HF_MIN(len, len_from);
|
len = HF_MIN(len, len_from);
|
||||||
@ -115,176 +99,148 @@ static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
|
|||||||
len = HF_MIN(len, len_to);
|
len = HF_MIN(len, len_to);
|
||||||
|
|
||||||
memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
|
memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src,
|
static inline void mangle_Overwrite(
|
||||||
size_t len, bool printable) {
|
run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
|
||||||
|
if (len == 0) {
|
||||||
if (len == 0) { return; }
|
return;
|
||||||
|
}
|
||||||
size_t maxToCopy = run->dynfile->size - off;
|
size_t maxToCopy = run->dynfile->size - off;
|
||||||
if (len > maxToCopy) { len = maxToCopy; }
|
if (len > maxToCopy) {
|
||||||
|
len = maxToCopy;
|
||||||
|
}
|
||||||
|
|
||||||
memmove(&run->dynfile->data[off], src, len);
|
memmove(&run->dynfile->data[off], src, len);
|
||||||
if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); }
|
if (printable) {
|
||||||
|
util_turnToPrintable(&run->dynfile->data[off], len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len,
|
static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
|
||||||
bool printable) {
|
if (run->dynfile->size >= run->global->mutate.maxInputSz) {
|
||||||
|
return 0;
|
||||||
if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; }
|
}
|
||||||
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
|
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
|
||||||
|
|
||||||
len = run->global->mutate.maxInputSz - run->dynfile->size;
|
len = run->global->mutate.maxInputSz - run->dynfile->size;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input_setSize(run, run->dynfile->size + len);
|
input_setSize(run, run->dynfile->size + len);
|
||||||
mangle_Move(run, off, off + len, run->dynfile->size);
|
mangle_Move(run, off, off + len, run->dynfile->size);
|
||||||
if (printable) { memset(&run->dynfile->data[off], ' ', len); }
|
if (printable) {
|
||||||
|
memset(&run->dynfile->data[off], ' ', len);
|
||||||
return len;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val,
|
|
||||||
size_t len, bool printable) {
|
|
||||||
|
|
||||||
len = mangle_Inflate(run, off, len, printable);
|
|
||||||
mangle_Overwrite(run, off, val, len, printable);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len,
|
|
||||||
bool printable) {
|
|
||||||
|
|
||||||
if (util_rnd64() % 2) {
|
|
||||||
|
|
||||||
mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) {
|
static inline void mangle_Insert(
|
||||||
|
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
|
||||||
|
len = mangle_Inflate(run, off, len, printable);
|
||||||
|
mangle_Overwrite(run, off, val, len, printable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
|
||||||
|
if (util_rnd64() & 1) {
|
||||||
|
mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
|
||||||
|
} else {
|
||||||
|
mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mangle_UseValueAt(
|
||||||
|
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
|
||||||
|
if (util_rnd64() & 1) {
|
||||||
|
mangle_Overwrite(run, off, val, len, printable);
|
||||||
|
} else {
|
||||||
|
mangle_Insert(run, off, val, len, printable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
|
||||||
|
/* No big deal if those two are overlapping */
|
||||||
size_t off1 = mangle_getOffSet(run);
|
size_t off1 = mangle_getOffSet(run);
|
||||||
size_t maxlen1 = run->dynfile->size - off1;
|
size_t maxlen1 = run->dynfile->size - off1;
|
||||||
|
|
||||||
size_t off2 = mangle_getOffSet(run);
|
size_t off2 = mangle_getOffSet(run);
|
||||||
size_t maxlen2 = run->dynfile->size - off2;
|
size_t maxlen2 = run->dynfile->size - off2;
|
||||||
|
|
||||||
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
|
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
|
||||||
uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
|
|
||||||
defer {
|
|
||||||
|
|
||||||
free(tmpbuf);
|
if (off1 == off2) {
|
||||||
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
memcpy(tmpbuf, &run->dynfile->data[off1], len);
|
|
||||||
memmove(&run->dynfile->data[off1], &run->dynfile->data[off2], len);
|
|
||||||
memcpy(&run->dynfile->data[off2], tmpbuf, len);
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (len / 2); i++) {
|
||||||
|
/*
|
||||||
|
* First - from the head, next from the tail. Don't worry about layout of the overlapping
|
||||||
|
* part - there's no good solution to that, and it can be left somewhat scrambled,
|
||||||
|
* while still preserving the entropy
|
||||||
|
*/
|
||||||
|
const uint8_t tmp1 = run->dynfile->data[off2 + i];
|
||||||
|
run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
|
||||||
|
run->dynfile->data[off1 + i] = tmp1;
|
||||||
|
const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
|
||||||
|
run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
|
||||||
|
run->dynfile->data[off1 + (len - 1) - i] = tmp2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) {
|
static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||||
|
|
||||||
/* Use a temp buf, as Insert/Inflate can change source bytes */
|
/* Use a temp buf, as Insert/Inflate can change source bytes */
|
||||||
uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
|
uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
|
||||||
defer {
|
defer {
|
||||||
|
|
||||||
free(tmpbuf);
|
free(tmpbuf);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
memmove(tmpbuf, &run->dynfile->data[off], len);
|
||||||
memcpy(tmpbuf, &run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
mangle_UseValue(run, tmpbuf, len, printable);
|
mangle_UseValue(run, tmpbuf, len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Bytes(run_t *run, bool printable) {
|
static void mangle_Bytes(run_t* run, bool printable) {
|
||||||
|
|
||||||
uint16_t buf;
|
uint16_t buf;
|
||||||
if (printable) {
|
if (printable) {
|
||||||
|
util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
|
||||||
util_rndBufPrintable((uint8_t *)&buf, sizeof(buf));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
buf = util_rnd64();
|
buf = util_rnd64();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite with random 1-2-byte values */
|
/* Overwrite with random 1-2-byte values */
|
||||||
size_t toCopy = util_rndGet(1, 2);
|
size_t toCopy = util_rndGet(1, 2);
|
||||||
mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable);
|
mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_ByteRepeatOverwrite(run_t *run, bool printable) {
|
static void mangle_ByteRepeat(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
size_t destOff = off + 1;
|
size_t destOff = off + 1;
|
||||||
size_t maxSz = run->dynfile->size - destOff;
|
size_t maxSz = run->dynfile->size - destOff;
|
||||||
|
|
||||||
/* No space to repeat */
|
/* No space to repeat */
|
||||||
if (!maxSz) {
|
if (!maxSz) {
|
||||||
|
|
||||||
mangle_Bytes(run, printable);
|
mangle_Bytes(run, printable);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = mangle_getLen(maxSz);
|
|
||||||
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mangle_ByteRepeatInsert(run_t *run, bool printable) {
|
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
|
||||||
size_t destOff = off + 1;
|
|
||||||
size_t maxSz = run->dynfile->size - destOff;
|
|
||||||
|
|
||||||
/* No space to repeat */
|
|
||||||
if (!maxSz) {
|
|
||||||
|
|
||||||
mangle_Bytes(run, printable);
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = mangle_getLen(maxSz);
|
size_t len = mangle_getLen(maxSz);
|
||||||
|
if (util_rnd64() & 0x1) {
|
||||||
len = mangle_Inflate(run, destOff, len, printable);
|
len = mangle_Inflate(run, destOff, len, printable);
|
||||||
|
}
|
||||||
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
|
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Bit(run_t *run, bool printable) {
|
static void mangle_Bit(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
|
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
|
||||||
if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); }
|
if (printable) {
|
||||||
|
util_turnToPrintable(&(run->dynfile->data[off]), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
||||||
const uint8_t val[8];
|
const uint8_t val[8];
|
||||||
const size_t size;
|
const size_t size;
|
||||||
|
|
||||||
} mangleMagicVals[] = {
|
} mangleMagicVals[] = {
|
||||||
|
|
||||||
/* 1B - No endianness */
|
/* 1B - No endianness */
|
||||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
|
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||||
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
|
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||||
@ -516,208 +472,160 @@ static const struct {
|
|||||||
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
|
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
|
||||||
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
|
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
|
||||||
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
|
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mangle_Magic(run_t *run, bool printable) {
|
static void mangle_Magic(run_t* run, bool printable) {
|
||||||
|
|
||||||
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
|
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
|
||||||
mangle_UseValue(run, mangleMagicVals[choice].val,
|
mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
|
||||||
mangleMagicVals[choice].size, printable);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_StaticDict(run_t *run, bool printable) {
|
static void mangle_StaticDict(run_t* run, bool printable) {
|
||||||
|
|
||||||
if (run->global->mutate.dictionaryCnt == 0) {
|
if (run->global->mutate.dictionaryCnt == 0) {
|
||||||
|
|
||||||
mangle_Bytes(run, printable);
|
mangle_Bytes(run, printable);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
|
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
|
||||||
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
|
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
|
||||||
run->global->mutate.dictionary[choice].len, printable);
|
run->global->mutate.dictionary[choice].len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) {
|
static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
|
||||||
|
if (!run->global->feedback.cmpFeedback) {
|
||||||
if (!run->global->feedback.cmpFeedback) { return NULL; }
|
return NULL;
|
||||||
cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap;
|
}
|
||||||
|
cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
|
||||||
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
|
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
|
||||||
if (cnt == 0) { return NULL; }
|
if (cnt == 0) {
|
||||||
if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); }
|
return NULL;
|
||||||
|
}
|
||||||
|
if (cnt > ARRAYSIZE(cmpf->valArr)) {
|
||||||
|
cnt = ARRAYSIZE(cmpf->valArr);
|
||||||
|
}
|
||||||
uint32_t choice = util_rndGet(0, cnt - 1);
|
uint32_t choice = util_rndGet(0, cnt - 1);
|
||||||
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
|
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
|
||||||
if (*len == 0) { return NULL; }
|
if (*len == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return cmpf->valArr[choice].val;
|
return cmpf->valArr[choice].val;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_ConstFeedbackDict(run_t *run, bool printable) {
|
static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
const uint8_t *val = mangle_FeedbackDict(run, &len);
|
const uint8_t* val = mangle_FeedbackDict(run, &len);
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
|
|
||||||
mangle_Bytes(run, printable);
|
mangle_Bytes(run, printable);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_UseValue(run, val, len, printable);
|
mangle_UseValue(run, val, len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_MemSet(run_t *run, bool printable) {
|
static void mangle_MemSet(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||||
int val =
|
int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
|
||||||
printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
|
|
||||||
|
if (util_rnd64() & 1) {
|
||||||
|
len = mangle_Inflate(run, off, len, printable);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&run->dynfile->data[off], val, len);
|
memset(&run->dynfile->data[off], val, len);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_RandomOverwrite(run_t *run, bool printable) {
|
static void mangle_MemClr(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
|
||||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
|
||||||
if (printable) {
|
|
||||||
|
|
||||||
util_rndBufPrintable(&run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
util_rndBuf(&run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mangle_RandomInsert(run_t *run, bool printable) {
|
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||||
|
int val = printable ? ' ' : 0;
|
||||||
|
|
||||||
|
if (util_rnd64() & 1) {
|
||||||
len = mangle_Inflate(run, off, len, printable);
|
len = mangle_Inflate(run, off, len, printable);
|
||||||
|
|
||||||
if (printable) {
|
|
||||||
|
|
||||||
util_rndBufPrintable(&run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
util_rndBuf(&run->dynfile->data[off], len);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&run->dynfile->data[off], val, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen,
|
static void mangle_RandomBuf(run_t* run, bool printable) {
|
||||||
uint64_t range, bool printable) {
|
size_t off = mangle_getOffSet(run);
|
||||||
|
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||||
|
|
||||||
|
if (util_rnd64() & 1) {
|
||||||
|
len = mangle_Inflate(run, off, len, printable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printable) {
|
||||||
|
util_rndBufPrintable(&run->dynfile->data[off], len);
|
||||||
|
} else {
|
||||||
|
util_rndBuf(&run->dynfile->data[off], len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mangle_AddSubWithRange(
|
||||||
|
run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
|
||||||
int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
|
int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
|
||||||
|
|
||||||
switch (varLen) {
|
switch (varLen) {
|
||||||
|
|
||||||
case 1: {
|
case 1: {
|
||||||
|
|
||||||
run->dynfile->data[off] += delta;
|
run->dynfile->data[off] += delta;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
|
|
||||||
int16_t val;
|
int16_t val;
|
||||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||||
if (util_rnd64() & 0x1) {
|
if (util_rnd64() & 0x1) {
|
||||||
|
|
||||||
val += delta;
|
val += delta;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Foreign endianess */
|
/* Foreign endianess */
|
||||||
val = __builtin_bswap16(val);
|
val = __builtin_bswap16(val);
|
||||||
val += delta;
|
val += delta;
|
||||||
val = __builtin_bswap16(val);
|
val = __builtin_bswap16(val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||||
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 4: {
|
case 4: {
|
||||||
|
|
||||||
int32_t val;
|
int32_t val;
|
||||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||||
if (util_rnd64() & 0x1) {
|
if (util_rnd64() & 0x1) {
|
||||||
|
|
||||||
val += delta;
|
val += delta;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Foreign endianess */
|
/* Foreign endianess */
|
||||||
val = __builtin_bswap32(val);
|
val = __builtin_bswap32(val);
|
||||||
val += delta;
|
val += delta;
|
||||||
val = __builtin_bswap32(val);
|
val = __builtin_bswap32(val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||||
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 8: {
|
case 8: {
|
||||||
|
|
||||||
int64_t val;
|
int64_t val;
|
||||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||||
if (util_rnd64() & 0x1) {
|
if (util_rnd64() & 0x1) {
|
||||||
|
|
||||||
val += delta;
|
val += delta;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Foreign endianess */
|
/* Foreign endianess */
|
||||||
val = __builtin_bswap64(val);
|
val = __builtin_bswap64(val);
|
||||||
val += delta;
|
val += delta;
|
||||||
val = __builtin_bswap64(val);
|
val = __builtin_bswap64(val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||||
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
LOG_F("Unknown variable length size: %zu", varLen);
|
LOG_F("Unknown variable length size: %zu", varLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_AddSub(run_t *run, bool printable) {
|
static void mangle_AddSub(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
|
|
||||||
/* 1,2,4,8 */
|
/* 1,2,4,8 */
|
||||||
size_t varLen = 1U << util_rndGet(0, 3);
|
size_t varLen = 1U << util_rndGet(0, 3);
|
||||||
if ((run->dynfile->size - off) < varLen) { varLen = 1; }
|
if ((run->dynfile->size - off) < varLen) {
|
||||||
|
varLen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t range;
|
uint64_t range;
|
||||||
switch (varLen) {
|
switch (varLen) {
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
range = 16;
|
range = 16;
|
||||||
break;
|
break;
|
||||||
@ -732,190 +640,170 @@ static void mangle_AddSub(run_t *run, bool printable) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_F("Invalid operand size: %zu", varLen);
|
LOG_F("Invalid operand size: %zu", varLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_AddSubWithRange(run, off, varLen, range, printable);
|
mangle_AddSubWithRange(run, off, varLen, range, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_IncByte(run_t *run, bool printable) {
|
static void mangle_IncByte(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
if (printable) {
|
if (printable) {
|
||||||
|
|
||||||
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
|
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
run->dynfile->data[off] += (uint8_t)1UL;
|
run->dynfile->data[off] += (uint8_t)1UL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_DecByte(run_t *run, bool printable) {
|
static void mangle_DecByte(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
if (printable) {
|
if (printable) {
|
||||||
|
|
||||||
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
|
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
run->dynfile->data[off] -= (uint8_t)1UL;
|
run->dynfile->data[off] -= (uint8_t)1UL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_NegByte(run_t *run, bool printable) {
|
static void mangle_NegByte(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
if (printable) {
|
if (printable) {
|
||||||
|
|
||||||
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
|
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
run->dynfile->data[off] = ~(run->dynfile->data[off]);
|
run->dynfile->data[off] = ~(run->dynfile->data[off]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Expand(run_t *run, bool printable) {
|
static void mangle_Expand(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
size_t len;
|
size_t len;
|
||||||
if (util_rnd64() % 16) {
|
if (util_rnd64() % 16) {
|
||||||
|
|
||||||
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
|
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
len = mangle_getLen(run->global->mutate.maxInputSz - off);
|
len = mangle_getLen(run->global->mutate.maxInputSz - off);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_Inflate(run, off, len, printable);
|
mangle_Inflate(run, off, len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) {
|
static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
|
||||||
|
if (run->dynfile->size <= 2U) {
|
||||||
if (run->dynfile->size <= 2U) { return; }
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t off_start = mangle_getOffSet(run);
|
size_t off_start = mangle_getOffSet(run);
|
||||||
size_t len = mangle_LenLeft(run, off_start);
|
size_t len = mangle_LenLeft(run, off_start);
|
||||||
if (len == 0) { return; }
|
if (len == 0) {
|
||||||
if (util_rnd64() % 16) {
|
return;
|
||||||
|
}
|
||||||
len = mangle_getLen(HF_MIN(16, len));
|
if (util_rnd64() % 16) {
|
||||||
|
len = mangle_getLen(HF_MIN(16, len));
|
||||||
} else {
|
} else {
|
||||||
|
len = mangle_getLen(len);
|
||||||
len = mangle_getLen(len);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t off_end = off_start + len;
|
size_t off_end = off_start + len;
|
||||||
size_t len_to_move = run->dynfile->size - off_end;
|
size_t len_to_move = run->dynfile->size - off_end;
|
||||||
|
|
||||||
mangle_Move(run, off_end, off_start, len_to_move);
|
mangle_Move(run, off_end, off_start, len_to_move);
|
||||||
input_setSize(run, run->dynfile->size - len);
|
input_setSize(run, run->dynfile->size - len);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
static void mangle_ASCIINum(run_t* run, bool printable) {
|
||||||
static void mangle_ASCIINum(run_t *run, bool printable) {
|
|
||||||
|
|
||||||
size_t len = util_rndGet(2, 8);
|
size_t len = util_rndGet(2, 8);
|
||||||
|
|
||||||
char buf[20];
|
char buf[20];
|
||||||
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
|
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
|
||||||
|
|
||||||
mangle_UseValue(run, (const uint8_t *)buf, len, printable);
|
mangle_UseValue(run, (const uint8_t*)buf, len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_ASCIINumChange(run_t *run, bool printable) {
|
static void mangle_ASCIINumChange(run_t* run, bool printable) {
|
||||||
|
|
||||||
size_t off = mangle_getOffSet(run);
|
size_t off = mangle_getOffSet(run);
|
||||||
|
|
||||||
/* Find a digit */
|
/* Find a digit */
|
||||||
for (; off < run->dynfile->size; off++) {
|
for (; off < run->dynfile->size; off++) {
|
||||||
|
if (isdigit(run->dynfile->data[off])) {
|
||||||
if (isdigit(run->dynfile->data[off])) { break; }
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (off == run->dynfile->size) {
|
size_t left = run->dynfile->size - off;
|
||||||
|
if (left == 0) {
|
||||||
mangle_Bytes(run, printable);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = HF_MIN(20, run->dynfile->size - off);
|
size_t len = 0;
|
||||||
char numbuf[21] = {};
|
uint64_t val = 0;
|
||||||
strncpy(numbuf, (const char *)&run->dynfile->data[off], len);
|
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
|
||||||
uint64_t val = (uint64_t)strtoull(numbuf, NULL, 10);
|
for (len = 0; (len < 20) && (len < left); len++) {
|
||||||
|
char c = run->dynfile->data[off + len];
|
||||||
switch (util_rndGet(0, 5)) {
|
if (!isdigit(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val *= 10;
|
||||||
|
val += (c - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (util_rndGet(0, 7)) {
|
||||||
case 0:
|
case 0:
|
||||||
val += util_rndGet(1, 256);
|
val++;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
val -= util_rndGet(1, 256);
|
val--;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
val *= util_rndGet(1, 256);
|
val *= 2;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
val /= util_rndGet(1, 256);
|
val /= 2;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
val = ~(val);
|
val = util_rnd64();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
val = util_rnd64();
|
val += util_rndGet(1, 256);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
val -= util_rndGet(1, 256);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
val = ~(val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_F("Invalid choice");
|
LOG_F("Invalid choice");
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
len = HF_MIN((size_t)snprintf(numbuf, sizeof(numbuf), "%" PRIu64, val), len);
|
char buf[20];
|
||||||
mangle_Overwrite(run, off, (const uint8_t *)numbuf, len, printable);
|
snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
|
||||||
|
|
||||||
|
mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Splice(run_t *run, bool printable) {
|
static void mangle_Splice(run_t* run, bool printable) {
|
||||||
|
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
|
||||||
const uint8_t *buf;
|
|
||||||
size_t sz = input_getRandomInputAsBuf(run, &buf);
|
|
||||||
if (!sz) {
|
|
||||||
|
|
||||||
mangle_Bytes(run, printable);
|
mangle_Bytes(run, printable);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = 0;
|
||||||
|
const uint8_t* buf = input_getRandomInputAsBuf(run, &sz);
|
||||||
|
if (!buf) {
|
||||||
|
LOG_E("input_getRandomInputAsBuf() returned no input");
|
||||||
|
mangle_Bytes(run, printable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!sz) {
|
||||||
|
mangle_Bytes(run, printable);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t remoteOff = mangle_getLen(sz) - 1;
|
size_t remoteOff = mangle_getLen(sz) - 1;
|
||||||
size_t len = mangle_getLen(sz - remoteOff);
|
size_t len = mangle_getLen(sz - remoteOff);
|
||||||
mangle_UseValue(run, &buf[remoteOff], len, printable);
|
mangle_UseValue(run, &buf[remoteOff], len, printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_Resize(run_t *run, bool printable) {
|
static void mangle_Resize(run_t* run, bool printable) {
|
||||||
|
|
||||||
ssize_t oldsz = run->dynfile->size;
|
ssize_t oldsz = run->dynfile->size;
|
||||||
ssize_t newsz = 0;
|
ssize_t newsz = 0;
|
||||||
|
|
||||||
uint64_t choice = util_rndGet(0, 32);
|
uint64_t choice = util_rndGet(0, 32);
|
||||||
switch (choice) {
|
switch (choice) {
|
||||||
|
|
||||||
case 0: /* Set new size arbitrarily */
|
case 0: /* Set new size arbitrarily */
|
||||||
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
|
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
|
||||||
break;
|
break;
|
||||||
@ -937,33 +825,24 @@ static void mangle_Resize(run_t *run, bool printable) {
|
|||||||
default:
|
default:
|
||||||
LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
|
LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (newsz < 1) {
|
||||||
if (newsz < 1) { newsz = 1; }
|
newsz = 1;
|
||||||
|
}
|
||||||
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
|
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
|
||||||
|
|
||||||
newsz = run->global->mutate.maxInputSz;
|
newsz = run->global->mutate.maxInputSz;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input_setSize(run, (size_t)newsz);
|
input_setSize(run, (size_t)newsz);
|
||||||
if (newsz > oldsz) {
|
if (newsz > oldsz) {
|
||||||
|
if (printable) {
|
||||||
if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); }
|
memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mangle_mangleContent(run_t *run, int speed_factor) {
|
void mangle_mangleContent(run_t* run, int speed_factor) {
|
||||||
|
|
||||||
static void (*const mangleFuncs[])(run_t * run, bool printable) = {
|
static void (*const mangleFuncs[])(run_t * run, bool printable) = {
|
||||||
|
|
||||||
/* Every *Insert or Expand expands file, so add more Shrink's */
|
|
||||||
mangle_Shrink,
|
|
||||||
mangle_Shrink,
|
|
||||||
mangle_Shrink,
|
|
||||||
mangle_Shrink,
|
mangle_Shrink,
|
||||||
mangle_Expand,
|
mangle_Expand,
|
||||||
mangle_Bit,
|
mangle_Bit,
|
||||||
@ -972,66 +851,57 @@ void mangle_mangleContent(run_t *run, int speed_factor) {
|
|||||||
mangle_NegByte,
|
mangle_NegByte,
|
||||||
mangle_AddSub,
|
mangle_AddSub,
|
||||||
mangle_MemSet,
|
mangle_MemSet,
|
||||||
|
mangle_MemClr,
|
||||||
mangle_MemSwap,
|
mangle_MemSwap,
|
||||||
mangle_MemCopy,
|
mangle_MemCopy,
|
||||||
mangle_Bytes,
|
mangle_Bytes,
|
||||||
mangle_ASCIINum,
|
mangle_ASCIINum,
|
||||||
mangle_ASCIINumChange,
|
mangle_ASCIINumChange,
|
||||||
mangle_ByteRepeatOverwrite,
|
mangle_ByteRepeat,
|
||||||
mangle_ByteRepeatInsert,
|
|
||||||
mangle_Magic,
|
mangle_Magic,
|
||||||
mangle_StaticDict,
|
mangle_StaticDict,
|
||||||
mangle_ConstFeedbackDict,
|
mangle_ConstFeedbackDict,
|
||||||
mangle_RandomOverwrite,
|
mangle_RandomBuf,
|
||||||
mangle_RandomInsert,
|
|
||||||
mangle_Splice,
|
mangle_Splice,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (run->mutationsPerRun == 0U) { return; }
|
if (run->mutationsPerRun == 0U) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (run->dynfile->size == 0U) {
|
if (run->dynfile->size == 0U) {
|
||||||
|
|
||||||
mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
|
mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t changesCnt = run->global->mutate.mutationsPerRun;
|
uint64_t changesCnt = run->global->mutate.mutationsPerRun;
|
||||||
|
|
||||||
if (speed_factor < 5) {
|
if (speed_factor < 5) {
|
||||||
|
|
||||||
changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
|
changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
|
||||||
|
|
||||||
} else if (speed_factor < 10) {
|
} else if (speed_factor < 10) {
|
||||||
|
|
||||||
changesCnt = run->global->mutate.mutationsPerRun;
|
changesCnt = run->global->mutate.mutationsPerRun;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
changesCnt = HF_MIN(speed_factor, 10);
|
||||||
changesCnt = HF_MIN(speed_factor, 12);
|
changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
|
||||||
changesCnt = HF_MAX(changesCnt, run->global->mutate.mutationsPerRun);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If last coverage acquisition was more than 5 secs ago, use splicing more
|
/* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
|
||||||
* frequently */
|
|
||||||
if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
|
if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
|
||||||
|
if (util_rnd64() & 0x1) {
|
||||||
if (util_rnd64() % 2) {
|
|
||||||
|
|
||||||
mangle_Splice(run, run->global->cfg.only_printable);
|
mangle_Splice(run, run->global->cfg.only_printable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint64_t x = 0; x < changesCnt; x++) {
|
for (uint64_t x = 0; x < changesCnt; x++) {
|
||||||
|
if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
|
||||||
|
/*
|
||||||
|
* mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary
|
||||||
|
* exists. If so, give it 50% chance of being used among all mangling functions.
|
||||||
|
*/
|
||||||
|
mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable);
|
||||||
|
} else {
|
||||||
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
|
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
|
||||||
mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
|
mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wmb();
|
wmb();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
return false;
|
||||||
|
|
||||||
// Read traces.
|
// 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.
|
if (!CorporaHashes.count(Name)) continue; // not in the corpus.
|
||||||
NumTraceFiles++;
|
NumTraceFiles++;
|
||||||
// Printf("=== %s\n", Name.c_str());
|
// Printf("=== %s\n", Name.c_str());
|
||||||
std::ifstream IF(SF.File);
|
std::ifstream IF2(SF.File);
|
||||||
while (std::getline(IF, L, '\n')) {
|
while (std::getline(IF2, L, '\n')) {
|
||||||
|
|
||||||
size_t FunctionNum = 0;
|
size_t FunctionNum = 0;
|
||||||
std::string DFTString;
|
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.
|
// we then request tags in [0,Size/2) and [Size/2, Size), and so on.
|
||||||
// Function number => DFT.
|
// Function number => DFT.
|
||||||
auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
|
auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
|
||||||
std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
|
// std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
|
||||||
std::unordered_set<std::string> Cov;
|
// std::unordered_set<std::string> Cov;
|
||||||
Command Cmd;
|
Command Cmd;
|
||||||
Cmd.addArgument(DFTBinary);
|
Cmd.addArgument(DFTBinary);
|
||||||
Cmd.addArgument(F.File);
|
Cmd.addArgument(F.File);
|
||||||
|
@ -46,7 +46,7 @@ template<typename T>
|
|||||||
fuzzer_allocator() = default;
|
fuzzer_allocator() = default;
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
fuzzer_allocator(const fuzzer_allocator<U>&) {}
|
explicit fuzzer_allocator(const fuzzer_allocator<U>&) {}
|
||||||
|
|
||||||
template<class Other>
|
template<class Other>
|
||||||
struct rebind { typedef fuzzer_allocator<Other> other; };
|
struct rebind { typedef fuzzer_allocator<Other> other; };
|
||||||
|
@ -49,7 +49,7 @@ typedef FixedWord<64> Word;
|
|||||||
class DictionaryEntry {
|
class DictionaryEntry {
|
||||||
public:
|
public:
|
||||||
DictionaryEntry() {}
|
DictionaryEntry() {}
|
||||||
DictionaryEntry(Word W) : W(W) {}
|
explicit DictionaryEntry(Word W) : W(W) {}
|
||||||
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
|
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
|
||||||
const Word &GetW() const { return W; }
|
const Word &GetW() const { return W; }
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class Dictionary {
|
|||||||
assert(Idx < Size);
|
assert(Idx < Size);
|
||||||
return DE[Idx];
|
return DE[Idx];
|
||||||
}
|
}
|
||||||
void push_back(DictionaryEntry DE) {
|
void push_back(const DictionaryEntry &DE) {
|
||||||
if (Size < kMaxDictSize)
|
if (Size < kMaxDictSize)
|
||||||
this->DE[Size++] = DE;
|
this->DE[Size++] = DE;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
namespace fuzzer {
|
namespace fuzzer {
|
||||||
class Random : public std::minstd_rand {
|
class Random : public std::minstd_rand {
|
||||||
public:
|
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()(); }
|
result_type operator()() { return this->std::minstd_rand::operator()(); }
|
||||||
size_t Rand() { return this->operator()(); }
|
size_t Rand() { return this->operator()(); }
|
||||||
size_t RandBool() { return Rand() % 2; }
|
size_t RandBool() { return Rand() % 2; }
|
||||||
|
@ -145,10 +145,10 @@ private:
|
|||||||
};
|
};
|
||||||
Region *Regions;
|
Region *Regions;
|
||||||
size_t NumRegions;
|
size_t NumRegions;
|
||||||
uint8_t *Start() { return Regions[0].Start; }
|
uint8_t *Start() const { return Regions[0].Start; }
|
||||||
uint8_t *Stop() { return Regions[NumRegions - 1].Stop; }
|
uint8_t *Stop() const { return Regions[NumRegions - 1].Stop; }
|
||||||
size_t Size() { return Stop() - Start(); }
|
size_t Size() const { return Stop() - Start(); }
|
||||||
size_t Idx(uint8_t *P) {
|
size_t Idx(uint8_t *P) const {
|
||||||
assert(P >= Start() && P < Stop());
|
assert(P >= Start() && P < Stop());
|
||||||
return P - Start();
|
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>.
|
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)
|
### Version ++3.00c (release)
|
||||||
- llvm_mode/ and gcc_plugin/ moved to instrumentation/
|
- llvm_mode/ and gcc_plugin/ moved to instrumentation/
|
||||||
- examples/ renamed to utils/
|
- examples/ renamed to utils/
|
||||||
@ -46,6 +117,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
- somewhere we broke -n dumb fuzzing, fixed
|
- somewhere we broke -n dumb fuzzing, fixed
|
||||||
- added afl_custom_describe to the custom mutator API to allow for easy
|
- added afl_custom_describe to the custom mutator API to allow for easy
|
||||||
mutation reproduction on crashing inputs
|
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
|
- instrumentation
|
||||||
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
||||||
very much!!
|
very much!!
|
||||||
|
@ -174,7 +174,7 @@
|
|||||||
|
|
||||||
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
||||||
used for getting basic block information at runtime.
|
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.
|
whereas Dynamorio is additionally available for ARM and AARCH64.
|
||||||
Dynamorio is also 10x faster than Pintool.
|
Dynamorio is also 10x faster than Pintool.
|
||||||
|
|
||||||
@ -182,7 +182,7 @@
|
|||||||
Dynamorio has a speed decrease of 98-99%
|
Dynamorio has a speed decrease of 98-99%
|
||||||
Pintool has a speed decrease of 99.5%
|
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.
|
only if Dynamorio fails too.
|
||||||
|
|
||||||
Dynamorio solutions:
|
Dynamorio solutions:
|
||||||
@ -205,6 +205,7 @@
|
|||||||
* QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
|
* QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
|
||||||
* Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
|
* Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
|
||||||
* S2E: [https://github.com/S2E](https://github.com/S2E)
|
* 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
|
* ... 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
|
For now, we support C/C++ library and Python module, collectivelly named as the
|
||||||
custom mutator.
|
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
|
Implemented by
|
||||||
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
||||||
- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
|
- 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
|
users or for some types of custom fuzzing setups. See [README.md](README.md) for the general
|
||||||
instruction manual.
|
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
|
## 1) Settings for all compilers
|
||||||
|
|
||||||
Starting with afl++ 3.0 there is only one compiler: afl-cc
|
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`
|
`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++).
|
||||||
|
|
||||||
|
|
||||||
Because (with the exception of the --afl-MODE command line option) the
|
Because (with the exception of the --afl-MODE command line option) the
|
||||||
compile-time tools do not accept afl specific command-line options, they
|
compile-time tools do not accept afl specific command-line options, they
|
||||||
make fairly broad use of environmental variables instead:
|
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.
|
- `AFL_LLVM_INSTRUMENT` - this configures the instrumentation mode.
|
||||||
Available options:
|
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)
|
CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
|
||||||
CFG - InsTrim instrumentation (see below)
|
CFG - InsTrim instrumentation (see below)
|
||||||
LTO - LTO instrumentation (see below)
|
LTO - LTO instrumentation (see below)
|
||||||
CTX - context sensitive instrumentation (see below)
|
CTX - context sensitive instrumentation (see below)
|
||||||
NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
|
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
|
In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
|
||||||
NGRAM, seperate the options with a comma "," then, e.g.:
|
NGRAM, seperate the options with a comma "," then, e.g.:
|
||||||
`AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4`
|
`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
|
the target. This must be equal or larger than the size the target was
|
||||||
compiled with.
|
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`
|
- `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
|
in config.h. Recommended values are 50-250MB - or more if your fuzzing
|
||||||
finds a huge amount of paths for large inputs.
|
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`
|
- Note that `AFL_POST_LIBRARY` is deprecated, use `AFL_CUSTOM_MUTATOR_LIBRARY`
|
||||||
instead (see below).
|
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
|
- Setting `AFL_CUSTOM_MUTATOR_LIBRARY` to a shared library with
|
||||||
afl_custom_fuzz() creates additional mutations through this library.
|
afl_custom_fuzz() creates additional mutations through this library.
|
||||||
If afl-fuzz is compiled with Python (which is autodetected during builing
|
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
|
some basic stats. This behavior is also automatically triggered when the
|
||||||
output from afl-fuzz is redirected to a file or to a pipe.
|
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
|
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
|
||||||
no valid terminal was detected (for virtual consoles)
|
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
|
normally done when starting up the forkserver and causes a pretty
|
||||||
significant performance drop.
|
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.
|
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`
|
The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` respectively.
|
||||||
respectively.
|
To enable tags (banner and afl_version) you should provide `AFL_STATSD_TAGS_FLAVOR` that matches
|
||||||
To get the most out of this, you should provide `AFL_STATSD_TAGS_FLAVOR` that
|
your StatsD server (see `AFL_STATSD_TAGS_FLAVOR`)
|
||||||
matches your StatsD server.
|
|
||||||
Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`.
|
- 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.
|
- Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash.
|
||||||
For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting
|
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
|
stack pointer in which QEMU can find the return address when `start addr` is
|
||||||
hit.
|
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
|
## 6) Settings for afl-cmin
|
||||||
|
|
||||||
The corpus minimization script offers very little customization:
|
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
|
a modest security risk on multi-user systems with rogue users, but should
|
||||||
be safe on dedicated fuzzing boxes.
|
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
|
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
|
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
|
In the following, we describe a variety of ideas that could be implemented
|
||||||
for future AFL++ versions.
|
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
|
## Analysis software
|
||||||
|
|
||||||
Currently analysis is done by using afl-plot, which is rather outdated.
|
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
|
It should be clickable which value is X and Y axis, zoom factor, log scaling
|
||||||
on-off, etc.
|
on-off, etc.
|
||||||
|
|
||||||
|
Mentor: vanhauser-thc
|
||||||
|
|
||||||
## WASM Instrumentation
|
## WASM Instrumentation
|
||||||
|
|
||||||
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
|
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
|
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!
|
## Your idea!
|
||||||
|
|
||||||
Finally, we are open to proposals!
|
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 |
|
| AFL flag | Power Schedule |
|
||||||
| ------------- | -------------------------- |
|
| ------------- | -------------------------- |
|
||||||
| `-p explore` (default)|  |
|
| `-p explore` |  |
|
||||||
| `-p fast` | =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) |
|
| `-p fast` (default)| =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) |
|
||||||
| `-p coe` |  |
|
| `-p coe` |  |
|
||||||
| `-p quad` |  |
|
| `-p quad` |  |
|
||||||
| `-p lin` |  |
|
| `-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
|
### The status bar
|
||||||
|
|
||||||
|
```
|
||||||
|
american fuzzy lop ++3.01a (default) [fast] {0}
|
||||||
|
```
|
||||||
|
|
||||||
The top line shows you which mode afl-fuzz is running in
|
The top line shows you which mode afl-fuzz is running in
|
||||||
(normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode")
|
(normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode")
|
||||||
and the version of afl++.
|
and the version of afl++.
|
||||||
Next to the version is the banner, which, if not set with -T by hand, will
|
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
|
either show the binary name being fuzzed, or the -M/-S main/secondary name for
|
||||||
parallel fuzzing.
|
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
|
### 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
|
#define _FILE_OFFSET_BITS 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
#include "android-ashmem.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -134,17 +130,34 @@
|
|||||||
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
|
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
|
||||||
#define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf)
|
#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 s8 interesting_8[INTERESTING_8_LEN];
|
||||||
extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
|
extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
|
||||||
extern s32
|
extern s32
|
||||||
interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN];
|
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 {
|
struct queue_entry {
|
||||||
|
|
||||||
u8 *fname; /* File name for the test case */
|
u8 *fname; /* File name for the test case */
|
||||||
u32 len; /* Input length */
|
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? */
|
bool trim_done, /* Trimmed? */
|
||||||
was_fuzzed, /* historical, but needed for MOpt */
|
was_fuzzed, /* historical, but needed for MOpt */
|
||||||
passed_det, /* Deterministic stages passed? */
|
passed_det, /* Deterministic stages passed? */
|
||||||
@ -152,7 +165,6 @@ struct queue_entry {
|
|||||||
var_behavior, /* Variable behavior? */
|
var_behavior, /* Variable behavior? */
|
||||||
favored, /* Currently favored? */
|
favored, /* Currently favored? */
|
||||||
fs_redundant, /* Marked as redundant in the fs? */
|
fs_redundant, /* Marked as redundant in the fs? */
|
||||||
fully_colorized, /* Do not run redqueen stage again */
|
|
||||||
is_ascii, /* Is the input just ascii text? */
|
is_ascii, /* Is the input just ascii text? */
|
||||||
disabled; /* Is disabled from fuzz selection */
|
disabled; /* Is disabled from fuzz selection */
|
||||||
|
|
||||||
@ -168,12 +180,19 @@ struct queue_entry {
|
|||||||
u8 *trace_mini; /* Trace bytes, if kept */
|
u8 *trace_mini; /* Trace bytes, if kept */
|
||||||
u32 tc_ref; /* Trace bytes ref count */
|
u32 tc_ref; /* Trace bytes ref count */
|
||||||
|
|
||||||
|
#ifdef INTROSPECTION
|
||||||
|
u32 bitsmap_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
double perf_score, /* performance score */
|
double perf_score, /* performance score */
|
||||||
weight;
|
weight;
|
||||||
|
|
||||||
u8 *testcase_buf; /* The testcase buffer, if loaded. */
|
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_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_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_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,
|
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_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
|
||||||
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
||||||
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
||||||
*afl_testcache_entries;
|
*afl_testcache_entries, *afl_kill_signal;
|
||||||
|
|
||||||
} afl_env_vars_t;
|
} afl_env_vars_t;
|
||||||
|
|
||||||
@ -385,7 +404,7 @@ struct afl_pass_stat {
|
|||||||
struct foreign_sync {
|
struct foreign_sync {
|
||||||
|
|
||||||
u8 * dir;
|
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. */
|
really makes no sense to haul them around as function parameters. */
|
||||||
u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
|
u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
|
||||||
total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key,
|
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;
|
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_total, /* Blocks subject to effector maps */
|
||||||
blocks_eff_select, /* Blocks selected as fuzzable */
|
blocks_eff_select, /* Blocks selected as fuzzable */
|
||||||
start_time, /* Unix start time (ms) */
|
start_time, /* Unix start time (ms) */
|
||||||
|
last_sync_time, /* Time of last sync */
|
||||||
last_path_time, /* Time for most recent path (ms) */
|
last_path_time, /* Time for most recent path (ms) */
|
||||||
last_crash_time, /* Time for most recent crash (ms) */
|
last_crash_time, /* Time for most recent crash (ms) */
|
||||||
last_hang_time; /* Time for most recent hang (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 */
|
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? */
|
s32 splicing_with; /* Splicing with which test case? */
|
||||||
|
|
||||||
u32 main_node_id, main_node_max; /* Main instance job splitting */
|
u32 main_node_id, main_node_max; /* Main instance job splitting */
|
||||||
@ -580,7 +601,8 @@ typedef struct afl_state {
|
|||||||
|
|
||||||
u32 rand_cnt; /* Random number counter */
|
u32 rand_cnt; /* Random number counter */
|
||||||
|
|
||||||
u64 rand_seed[4];
|
/* unsigned long rand_seed[3]; would also work */
|
||||||
|
AFL_RAND_RETURN rand_seed[3];
|
||||||
s64 init_seed;
|
s64 init_seed;
|
||||||
|
|
||||||
u64 total_cal_us, /* Total calibration time (us) */
|
u64 total_cal_us, /* Total calibration time (us) */
|
||||||
@ -625,6 +647,10 @@ typedef struct afl_state {
|
|||||||
/* cmplog forkserver ids */
|
/* cmplog forkserver ids */
|
||||||
s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
|
s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
|
||||||
u32 cmplog_prev_timed_out;
|
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 afl_pass_stat *pass_stats;
|
||||||
struct cmp_map * orig_cmp_map;
|
struct cmp_map * orig_cmp_map;
|
||||||
@ -634,10 +660,10 @@ typedef struct afl_state {
|
|||||||
|
|
||||||
unsigned long long int last_avg_exec_update;
|
unsigned long long int last_avg_exec_update;
|
||||||
u32 last_avg_execs;
|
u32 last_avg_execs;
|
||||||
float last_avg_execs_saved;
|
double last_avg_execs_saved;
|
||||||
|
|
||||||
/* foreign sync */
|
/* foreign sync */
|
||||||
#define FOREIGN_SYNCS_MAX 32
|
#define FOREIGN_SYNCS_MAX 32U
|
||||||
u8 foreign_sync_cnt;
|
u8 foreign_sync_cnt;
|
||||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||||
|
|
||||||
@ -728,6 +754,7 @@ typedef struct afl_state {
|
|||||||
char mutation[8072];
|
char mutation[8072];
|
||||||
char m_tmp[4096];
|
char m_tmp[4096];
|
||||||
FILE *introspection_file;
|
FILE *introspection_file;
|
||||||
|
u32 bitsmap_size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} afl_state_t;
|
} afl_state_t;
|
||||||
@ -1014,12 +1041,12 @@ void write_bitmap(afl_state_t *);
|
|||||||
u32 count_bits(afl_state_t *, u8 *);
|
u32 count_bits(afl_state_t *, u8 *);
|
||||||
u32 count_bytes(afl_state_t *, u8 *);
|
u32 count_bytes(afl_state_t *, u8 *);
|
||||||
u32 count_non_255_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
|
#ifdef WORD_SIZE_64
|
||||||
void simplify_trace(afl_state_t *, u64 *);
|
void discover_word(u8 *ret, u64 *current, u64 *virgin);
|
||||||
void classify_counts(afl_forkserver_t *);
|
|
||||||
#else
|
#else
|
||||||
void simplify_trace(afl_state_t *, u32 *);
|
void discover_word(u8 *ret, u32 *current, u32 *virgin);
|
||||||
void classify_counts(afl_forkserver_t *);
|
|
||||||
#endif
|
#endif
|
||||||
void init_count_class16(void);
|
void init_count_class16(void);
|
||||||
void minimize_bits(afl_state_t *, u8 *, u8 *);
|
void minimize_bits(afl_state_t *, u8 *, u8 *);
|
||||||
@ -1028,6 +1055,7 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
|||||||
#endif
|
#endif
|
||||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||||
u8 has_new_bits(afl_state_t *, u8 *);
|
u8 has_new_bits(afl_state_t *, u8 *);
|
||||||
|
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||||
|
|
||||||
/* Extras */
|
/* Extras */
|
||||||
|
|
||||||
@ -1042,9 +1070,10 @@ void destroy_extras(afl_state_t *);
|
|||||||
|
|
||||||
/* Stats */
|
/* Stats */
|
||||||
|
|
||||||
|
void load_stats_file(afl_state_t *);
|
||||||
void write_setup_file(afl_state_t *, u32, char **);
|
void write_setup_file(afl_state_t *, u32, char **);
|
||||||
void write_stats_file(afl_state_t *, double, double, double);
|
void write_stats_file(afl_state_t *, u32, double, double, double);
|
||||||
void maybe_update_plot_file(afl_state_t *, double, double);
|
void maybe_update_plot_file(afl_state_t *, u32, double, double);
|
||||||
void show_stats(afl_state_t *);
|
void show_stats(afl_state_t *);
|
||||||
void show_init_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);
|
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
|
||||||
|
|
||||||
/* RedQueen */
|
/* RedQueen */
|
||||||
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
|
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len);
|
||||||
u64 exec_cksum);
|
|
||||||
|
|
||||||
/* xoshiro256** */
|
/* our RNG wrapper */
|
||||||
uint64_t rand_next(afl_state_t *afl);
|
AFL_RAND_RETURN rand_next(afl_state_t *afl);
|
||||||
|
|
||||||
/* probability between 0.0 and 1.0 */
|
/* probability between 0.0 and 1.0 */
|
||||||
double rand_next_percent(afl_state_t *afl);
|
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);
|
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||||
ALLOC_CHECK_RESULT(ret, size);
|
ALLOC_CHECK_RESULT(ret, size);
|
||||||
|
|
||||||
ret += ALLOC_OFF_HEAD;
|
ret = (char *)ret + ALLOC_OFF_HEAD;
|
||||||
|
|
||||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||||
ALLOC_S(ret) = size;
|
ALLOC_S(ret) = size;
|
||||||
@ -311,7 +311,7 @@ static inline void DFL_ck_free(void *mem) {
|
|||||||
|
|
||||||
ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
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 */
|
#endif /* !DEBUG_BUILD */
|
||||||
|
|
||||||
old_size = ALLOC_S(orig);
|
old_size = ALLOC_S(orig);
|
||||||
orig -= ALLOC_OFF_HEAD;
|
orig = (char *)orig - ALLOC_OFF_HEAD;
|
||||||
|
|
||||||
ALLOC_CHECK_SIZE(old_size);
|
ALLOC_CHECK_SIZE(old_size);
|
||||||
|
|
||||||
@ -363,10 +363,11 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
|||||||
|
|
||||||
if (orig) {
|
if (orig) {
|
||||||
|
|
||||||
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
|
memcpy((char *)ret + ALLOC_OFF_HEAD, (char *)orig + ALLOC_OFF_HEAD,
|
||||||
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
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);
|
free(orig);
|
||||||
|
|
||||||
@ -374,13 +375,13 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
|||||||
|
|
||||||
#endif /* ^!DEBUG_BUILD */
|
#endif /* ^!DEBUG_BUILD */
|
||||||
|
|
||||||
ret += ALLOC_OFF_HEAD;
|
ret = (char *)ret + ALLOC_OFF_HEAD;
|
||||||
|
|
||||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||||
ALLOC_S(ret) = size;
|
ALLOC_S(ret) = size;
|
||||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
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;
|
return ret;
|
||||||
|
|
||||||
@ -401,7 +402,7 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
|
|||||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||||
ALLOC_CHECK_RESULT(ret, size);
|
ALLOC_CHECK_RESULT(ret, size);
|
||||||
|
|
||||||
ret += ALLOC_OFF_HEAD;
|
ret = (char *)ret + ALLOC_OFF_HEAD;
|
||||||
|
|
||||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||||
ALLOC_S(ret) = size;
|
ALLOC_S(ret) = size;
|
||||||
|
@ -1,35 +1,8 @@
|
|||||||
/*
|
|
||||||
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__
|
#ifdef __ANDROID__
|
||||||
|
#ifndef _ANDROID_ASHMEM_H
|
||||||
|
#define _ANDROID_ASHMEM_H
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/shm.h>
|
|
||||||
#include <linux/ashmem.h>
|
#include <linux/ashmem.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@ -40,7 +13,6 @@
|
|||||||
#define shmdt bionic_shmdt
|
#define shmdt bionic_shmdt
|
||||||
#define shmget bionic_shmget
|
#define shmget bionic_shmget
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
#undef shmat
|
#undef shmat
|
||||||
#undef shmctl
|
#undef shmctl
|
||||||
@ -50,13 +22,13 @@
|
|||||||
|
|
||||||
#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;
|
int ret = 0;
|
||||||
if (__cmd == IPC_RMID) {
|
if (__cmd == IPC_RMID) {
|
||||||
|
|
||||||
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
|
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);
|
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
|
||||||
close(__shmid);
|
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;
|
(void)__shmflg;
|
||||||
int fd, ret;
|
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;
|
(void)__shmflg;
|
||||||
int size;
|
int size;
|
||||||
@ -106,7 +78,6 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __ANDROID__ */
|
#endif /* !_ANDROID_ASHMEM_H */
|
||||||
|
#endif /* !__ANDROID__ */
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ -30,24 +30,25 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#define CMPLOG_LVL_MAX 3
|
||||||
|
|
||||||
#define CMP_MAP_W 65536
|
#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 CMP_MAP_RTN_H (CMP_MAP_H / 4)
|
||||||
|
|
||||||
#define SHAPE_BYTES(x) (x + 1)
|
#define SHAPE_BYTES(x) (x + 1)
|
||||||
|
|
||||||
#define CMP_TYPE_INS 0
|
#define CMP_TYPE_INS 1
|
||||||
#define CMP_TYPE_RTN 1
|
#define CMP_TYPE_RTN 2
|
||||||
|
|
||||||
struct cmp_header {
|
struct cmp_header {
|
||||||
|
|
||||||
unsigned hits : 20;
|
unsigned hits : 24;
|
||||||
|
unsigned id : 24;
|
||||||
unsigned cnt : 20;
|
unsigned shape : 5;
|
||||||
unsigned id : 16;
|
unsigned type : 2;
|
||||||
|
unsigned attribute : 4;
|
||||||
unsigned shape : 5; // from 0 to 31
|
unsigned reserved : 5;
|
||||||
unsigned type : 1;
|
|
||||||
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
@ -55,6 +56,8 @@ struct cmp_operands {
|
|||||||
|
|
||||||
u64 v0;
|
u64 v0;
|
||||||
u64 v1;
|
u64 v1;
|
||||||
|
u64 v0_128;
|
||||||
|
u64 v1_128;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#define STRINGIFY_VAL_SIZE_MAX (16)
|
#define STRINGIFY_VAL_SIZE_MAX (16)
|
||||||
|
|
||||||
void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
|
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);
|
void check_environment_vars(char **env);
|
||||||
|
|
||||||
char **argv_cpy_dup(int argc, char **argv);
|
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_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_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||||
char * get_afl_env(char *env);
|
char * get_afl_env(char *env);
|
||||||
|
u8 * get_libqasan_path(u8 *own_loc);
|
||||||
|
|
||||||
extern u8 be_quiet;
|
extern u8 be_quiet;
|
||||||
extern u8 *doc_path; /* path to documentation dir */
|
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);
|
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
|
/* Read a bitmap from file fname to memory
|
||||||
This is for the -B option again. */
|
This is for the -B option again. */
|
||||||
|
|
||||||
|
109
include/config.h
109
include/config.h
@ -10,7 +10,7 @@
|
|||||||
Dominik Maier <mail@dmnk.co>
|
Dominik Maier <mail@dmnk.co>
|
||||||
|
|
||||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -23,12 +23,10 @@
|
|||||||
#ifndef _HAVE_CONFIG_H
|
#ifndef _HAVE_CONFIG_H
|
||||||
#define _HAVE_CONFIG_H
|
#define _HAVE_CONFIG_H
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
/* Version string: */
|
/* Version string: */
|
||||||
|
|
||||||
// c = release, d = volatile github dev, e = experimental branch
|
// c = release, a = volatile github dev, e = experimental branch
|
||||||
#define VERSION "++3.00c"
|
#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
|
/* Comment out to disable terminal colors (note that this makes afl-analyze
|
||||||
a lot less nice): */
|
a lot less nice): */
|
||||||
|
|
||||||
#define USE_COLOR
|
#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
|
/* StatsD config
|
||||||
Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
|
Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
|
||||||
variable.
|
variable.
|
||||||
@ -52,7 +94,7 @@
|
|||||||
/* If you want to have the original afl internal memory corruption checks.
|
/* 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". */
|
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: */
|
/* 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,
|
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||||
also used for detecting hangs; the actual value is auto-scaled: */
|
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): */
|
/* Timeout rounding factor when auto-scaling (milliseconds): */
|
||||||
|
|
||||||
#define EXEC_TM_ROUND 20
|
#define EXEC_TM_ROUND 20U
|
||||||
|
|
||||||
/* 64bit arch MACRO */
|
/* 64bit arch MACRO */
|
||||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||||
@ -76,48 +118,48 @@
|
|||||||
|
|
||||||
/* Default memory limit for child process (MB) 0 = disabled : */
|
/* 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 : */
|
/* 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 : */
|
/* 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
|
/* Number of calibration cycles per every new test case (and for test
|
||||||
cases that show variable behavior): */
|
cases that show variable behavior): */
|
||||||
|
|
||||||
#define CAL_CYCLES 8
|
#define CAL_CYCLES 8U
|
||||||
#define CAL_CYCLES_LONG 40
|
#define CAL_CYCLES_LONG 40U
|
||||||
|
|
||||||
/* Number of subsequent timeouts before abandoning an input file: */
|
/* 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: */
|
/* Maximum number of unique hangs or crashes to record: */
|
||||||
|
|
||||||
#define KEEP_UNIQUE_HANG 500
|
#define KEEP_UNIQUE_HANG 500U
|
||||||
#define KEEP_UNIQUE_CRASH 5000
|
#define KEEP_UNIQUE_CRASH 5000U
|
||||||
|
|
||||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||||
|
|
||||||
#define HAVOC_CYCLES 256
|
#define HAVOC_CYCLES 256U
|
||||||
#define HAVOC_CYCLES_INIT 1024
|
#define HAVOC_CYCLES_INIT 1024U
|
||||||
|
|
||||||
/* Maximum multiplier for the above (should be a power of two, beware
|
/* Maximum multiplier for the above (should be a power of two, beware
|
||||||
of 32-bit int overflows): */
|
of 32-bit int overflows): */
|
||||||
|
|
||||||
#define HAVOC_MAX_MULT 64
|
#define HAVOC_MAX_MULT 64U
|
||||||
#define HAVOC_MAX_MULT_MOPT 64
|
#define HAVOC_MAX_MULT_MOPT 64U
|
||||||
|
|
||||||
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
||||||
|
|
||||||
#define HAVOC_MIN 12
|
#define HAVOC_MIN 12U
|
||||||
|
|
||||||
/* Power Schedule Divisor */
|
/* Power Schedule Divisor */
|
||||||
#define POWER_BETA 1
|
#define POWER_BETA 1U
|
||||||
#define MAX_FACTOR (POWER_BETA * 32)
|
#define MAX_FACTOR (POWER_BETA * 32)
|
||||||
|
|
||||||
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
|
/* 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
|
In other words, the default (n = 4) produces 2, 4, 8, 16
|
||||||
stacked tweaks: */
|
stacked tweaks: */
|
||||||
|
|
||||||
#define HAVOC_STACK_POW2 4
|
#define HAVOC_STACK_POW2 4U
|
||||||
|
|
||||||
/* Caps on block sizes for cloning and deletion operations. Each of these
|
/* Caps on block sizes for cloning and deletion operations. Each of these
|
||||||
ranges has a 33% probability of getting picked, except for the first
|
ranges has a 33% probability of getting picked, except for the first
|
||||||
two cycles where smaller blocks are favored: */
|
two cycles where smaller blocks are favored: */
|
||||||
|
|
||||||
#define HAVOC_BLK_SMALL 32
|
#define HAVOC_BLK_SMALL 32U
|
||||||
#define HAVOC_BLK_MEDIUM 128
|
#define HAVOC_BLK_MEDIUM 128U
|
||||||
#define HAVOC_BLK_LARGE 1500
|
#define HAVOC_BLK_LARGE 1500U
|
||||||
|
|
||||||
/* Extra-large blocks, selected very rarely (<5% of the time): */
|
/* 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
|
/* Probabilities of skipping non-favored entries in the queue, expressed as
|
||||||
percentages: */
|
percentages: */
|
||||||
@ -169,9 +211,11 @@
|
|||||||
#define TRIM_START_STEPS 16
|
#define TRIM_START_STEPS 16
|
||||||
#define TRIM_END_STEPS 1024
|
#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: */
|
/* The same, for the test case minimizer: */
|
||||||
|
|
||||||
@ -236,6 +280,11 @@
|
|||||||
|
|
||||||
#define SYNC_INTERVAL 8
|
#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): */
|
/* Output directory reuse grace period (minutes): */
|
||||||
|
|
||||||
#define OUTPUT_GRACE 25
|
#define OUTPUT_GRACE 25
|
||||||
@ -363,7 +412,7 @@
|
|||||||
after changing this - otherwise, SEGVs may ensue. */
|
after changing this - otherwise, SEGVs may ensue. */
|
||||||
|
|
||||||
#define MAP_SIZE_POW2 16
|
#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): */
|
/* 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 *
|
* 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
|
#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 */
|
#endif /* ^MESSAGES_TO_STDOUT */
|
||||||
|
|
||||||
/* Show a prefixed warning. */
|
/* Show a prefixed warning. */
|
||||||
@ -224,7 +296,7 @@
|
|||||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||||
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
|
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||||
__FILE__, __LINE__); \
|
__FILE__, (u32)__LINE__); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
\
|
\
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -237,7 +309,7 @@
|
|||||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
|
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||||
__FILE__, __LINE__); \
|
__FILE__, (u32)__LINE__); \
|
||||||
abort(); \
|
abort(); \
|
||||||
\
|
\
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -251,7 +323,7 @@
|
|||||||
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
|
||||||
"\n[-] SYSTEM ERROR : " cRST x); \
|
"\n[-] SYSTEM ERROR : " cRST x); \
|
||||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \
|
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)); \
|
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
\
|
\
|
||||||
@ -275,8 +347,8 @@
|
|||||||
#define DEBUGF(x...) \
|
#define DEBUGF(x...) \
|
||||||
do { \
|
do { \
|
||||||
\
|
\
|
||||||
SAYF(cMGN "[D] " cBRI "DEBUG: " cRST x); \
|
fprintf(stderr, cMGN "[D] " cBRI "DEBUG: " cRST x); \
|
||||||
SAYF(cRST ""); \
|
fprintf(stderr, cRST ""); \
|
||||||
\
|
\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_CC",
|
"AFL_CC",
|
||||||
"AFL_CMIN_ALLOW_ANY",
|
"AFL_CMIN_ALLOW_ANY",
|
||||||
"AFL_CMIN_CRASHES_ONLY",
|
"AFL_CMIN_CRASHES_ONLY",
|
||||||
|
"AFL_CMPLOG_ONLY_NEW",
|
||||||
"AFL_CODE_END",
|
"AFL_CODE_END",
|
||||||
"AFL_CODE_START",
|
"AFL_CODE_START",
|
||||||
"AFL_COMPCOV_BINNAME",
|
"AFL_COMPCOV_BINNAME",
|
||||||
@ -42,11 +43,13 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_DEBUG_GDB",
|
"AFL_DEBUG_GDB",
|
||||||
"AFL_DISABLE_TRIM",
|
"AFL_DISABLE_TRIM",
|
||||||
"AFL_DONT_OPTIMIZE",
|
"AFL_DONT_OPTIMIZE",
|
||||||
|
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||||
"AFL_DUMB_FORKSRV",
|
"AFL_DUMB_FORKSRV",
|
||||||
"AFL_ENTRYPOINT",
|
"AFL_ENTRYPOINT",
|
||||||
"AFL_EXIT_WHEN_DONE",
|
"AFL_EXIT_WHEN_DONE",
|
||||||
"AFL_FAST_CAL",
|
"AFL_FAST_CAL",
|
||||||
"AFL_FORCE_UI",
|
"AFL_FORCE_UI",
|
||||||
|
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||||
"AFL_GCC_ALLOWLIST",
|
"AFL_GCC_ALLOWLIST",
|
||||||
"AFL_GCC_DENYLIST",
|
"AFL_GCC_DENYLIST",
|
||||||
"AFL_GCC_BLOCKLIST",
|
"AFL_GCC_BLOCKLIST",
|
||||||
@ -58,9 +61,11 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_FORKSRV_INIT_TMOUT",
|
"AFL_FORKSRV_INIT_TMOUT",
|
||||||
"AFL_HARDEN",
|
"AFL_HARDEN",
|
||||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
||||||
|
"AFL_IGNORE_UNKNOWN_ENVS",
|
||||||
"AFL_IMPORT_FIRST",
|
"AFL_IMPORT_FIRST",
|
||||||
"AFL_INST_LIBS",
|
"AFL_INST_LIBS",
|
||||||
"AFL_INST_RATIO",
|
"AFL_INST_RATIO",
|
||||||
|
"AFL_KILL_SIGNAL",
|
||||||
"AFL_KEEP_TRACES",
|
"AFL_KEEP_TRACES",
|
||||||
"AFL_KEEP_ASSEMBLY",
|
"AFL_KEEP_ASSEMBLY",
|
||||||
"AFL_LD_HARD_FAIL",
|
"AFL_LD_HARD_FAIL",
|
||||||
@ -78,8 +83,8 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_LLVM_CTX",
|
"AFL_LLVM_CTX",
|
||||||
"AFL_LLVM_DICT2FILE",
|
"AFL_LLVM_DICT2FILE",
|
||||||
"AFL_LLVM_DOCUMENT_IDS",
|
"AFL_LLVM_DOCUMENT_IDS",
|
||||||
"AFL_LLVM_INSTRUMENT",
|
|
||||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||||
|
"AFL_LLVM_INSTRUMENT",
|
||||||
"AFL_LLVM_LTO_AUTODICTIONARY",
|
"AFL_LLVM_LTO_AUTODICTIONARY",
|
||||||
"AFL_LLVM_AUTODICTIONARY",
|
"AFL_LLVM_AUTODICTIONARY",
|
||||||
"AFL_LLVM_SKIPSINGLEBLOCK",
|
"AFL_LLVM_SKIPSINGLEBLOCK",
|
||||||
@ -103,6 +108,10 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_NO_ARITH",
|
"AFL_NO_ARITH",
|
||||||
"AFL_NO_AUTODICT",
|
"AFL_NO_AUTODICT",
|
||||||
"AFL_NO_BUILTIN",
|
"AFL_NO_BUILTIN",
|
||||||
|
#if defined USE_COLOR && !defined ALWAYS_COLORED
|
||||||
|
"AFL_NO_COLOR",
|
||||||
|
"AFL_NO_COLOUR",
|
||||||
|
#endif
|
||||||
"AFL_NO_CPU_RED",
|
"AFL_NO_CPU_RED",
|
||||||
"AFL_NO_FORKSRV",
|
"AFL_NO_FORKSRV",
|
||||||
"AFL_NO_UI",
|
"AFL_NO_UI",
|
||||||
@ -122,6 +131,7 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_QEMU_DEBUG_MAPS",
|
"AFL_QEMU_DEBUG_MAPS",
|
||||||
"AFL_QEMU_DISABLE_CACHE",
|
"AFL_QEMU_DISABLE_CACHE",
|
||||||
"AFL_QEMU_DRIVER_NO_HOOK",
|
"AFL_QEMU_DRIVER_NO_HOOK",
|
||||||
|
"AFL_QEMU_FORCE_DFL",
|
||||||
"AFL_QEMU_PERSISTENT_ADDR",
|
"AFL_QEMU_PERSISTENT_ADDR",
|
||||||
"AFL_QEMU_PERSISTENT_CNT",
|
"AFL_QEMU_PERSISTENT_CNT",
|
||||||
"AFL_QEMU_PERSISTENT_GPR",
|
"AFL_QEMU_PERSISTENT_GPR",
|
||||||
@ -157,6 +167,7 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_WINE_PATH",
|
"AFL_WINE_PATH",
|
||||||
"AFL_NO_SNAPSHOT",
|
"AFL_NO_SNAPSHOT",
|
||||||
"AFL_EXPAND_HAVOC_NOW",
|
"AFL_EXPAND_HAVOC_NOW",
|
||||||
|
"AFL_USE_QASAN",
|
||||||
NULL
|
NULL
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,7 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
FILE *plot_file; /* Gnuplot output file */
|
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? */
|
u32 last_run_timed_out; /* Traced process timed out? */
|
||||||
|
|
||||||
u8 last_kill_signal; /* Signal that killed the child */
|
u8 last_kill_signal; /* Signal that killed the child */
|
||||||
@ -83,6 +83,8 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
bool uses_asan; /* Target uses ASAN? */
|
bool uses_asan; /* Target uses ASAN? */
|
||||||
|
|
||||||
|
bool debug; /* debug mode? */
|
||||||
|
|
||||||
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
||||||
u8 crash_exitcode; /* The 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);
|
void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len);
|
||||||
|
|
||||||
|
u8 kill_signal;
|
||||||
|
|
||||||
} afl_forkserver_t;
|
} afl_forkserver_t;
|
||||||
|
|
||||||
typedef enum fsrv_run_result {
|
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_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
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);
|
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,
|
fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
|
||||||
volatile u8 *stop_soon_p);
|
volatile u8 *stop_soon_p);
|
||||||
void afl_fsrv_killall(void);
|
void afl_fsrv_killall(void);
|
||||||
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
|
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
|
||||||
|
void afl_fsrv_kill(afl_forkserver_t *fsrv);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#define MSG_FORK_ON_APPLE \
|
#define MSG_FORK_ON_APPLE \
|
||||||
|
@ -51,6 +51,7 @@ typedef struct sharedmem {
|
|||||||
size_t map_size; /* actual allocated size */
|
size_t map_size; /* actual allocated size */
|
||||||
|
|
||||||
int cmplog_mode;
|
int cmplog_mode;
|
||||||
|
int shmemfuzz_mode;
|
||||||
struct cmp_map *cmp_map;
|
struct cmp_map *cmp_map;
|
||||||
|
|
||||||
} sharedmem_t;
|
} sharedmem_t;
|
||||||
|
@ -25,10 +25,15 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
typedef uint32_t u32;
|
typedef uint32_t u32;
|
||||||
|
#ifdef WORD_SIZE_64
|
||||||
|
typedef unsigned __int128 uint128_t;
|
||||||
|
typedef uint128_t u128;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Extended forkserver option values */
|
/* Extended forkserver option values */
|
||||||
|
|
||||||
@ -50,7 +55,7 @@ typedef uint32_t u32;
|
|||||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||||
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
|
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
|
||||||
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
|
// 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_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
|
||||||
#define FS_OPT_SET_MAPSIZE(x) \
|
#define FS_OPT_SET_MAPSIZE(x) \
|
||||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||||
@ -61,6 +66,10 @@ typedef int8_t s8;
|
|||||||
typedef int16_t s16;
|
typedef int16_t s16;
|
||||||
typedef int32_t s32;
|
typedef int32_t s32;
|
||||||
typedef int64_t s64;
|
typedef int64_t s64;
|
||||||
|
#ifdef WORD_SIZE_64
|
||||||
|
typedef __int128 int128_t;
|
||||||
|
typedef int128_t s128;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) \
|
#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
|
#ifdef AFL_LLVM_PASS
|
||||||
#if defined(__linux__) || !defined(__ANDROID__)
|
#if defined(__linux__) || !defined(__ANDROID__)
|
||||||
#define AFL_SR(s) (srandom(s))
|
#define AFL_SR(s) (srandom(s))
|
||||||
|
@ -200,7 +200,7 @@ struct InsTrim : public ModulePass {
|
|||||||
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
|
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
|
||||||
|
|
||||||
if (ctx_str)
|
if (ctx_str)
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLContext = new GlobalVariable(
|
AFLContext = new GlobalVariable(
|
||||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||||
#else
|
#else
|
||||||
@ -211,7 +211,7 @@ struct InsTrim : public ModulePass {
|
|||||||
|
|
||||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||||
if (ngram_size)
|
if (ngram_size)
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLPrevLoc = new GlobalVariable(
|
AFLPrevLoc = new GlobalVariable(
|
||||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||||
@ -224,7 +224,7 @@ struct InsTrim : public ModulePass {
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLPrevLoc = new GlobalVariable(
|
AFLPrevLoc = new GlobalVariable(
|
||||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||||
#else
|
#else
|
||||||
@ -407,10 +407,10 @@ struct InsTrim : public ModulePass {
|
|||||||
// does the function have calls? and is any of the calls larger than
|
// does the function have calls? and is any of the calls larger than
|
||||||
// one basic block?
|
// one basic block?
|
||||||
has_calls = 0;
|
has_calls = 0;
|
||||||
for (auto &BB : F) {
|
for (auto &BB2 : F) {
|
||||||
|
|
||||||
if (has_calls) break;
|
if (has_calls) break;
|
||||||
for (auto &IN : BB) {
|
for (auto &IN : BB2) {
|
||||||
|
|
||||||
CallInst *callInst = nullptr;
|
CallInst *callInst = nullptr;
|
||||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||||
@ -454,12 +454,12 @@ struct InsTrim : public ModulePass {
|
|||||||
|
|
||||||
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
|
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
|
||||||
DenseMap<BasicBlock *, unsigned> PredMap;
|
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;
|
BasicBlock *PBB = *PI;
|
||||||
auto It = PredMap.insert({PBB, genLabel()});
|
auto It = PredMap.insert({PBB, genLabel()});
|
||||||
unsigned Label = It.first->second;
|
unsigned Label = It.first->second;
|
||||||
cur_loc = Label;
|
// cur_loc = Label;
|
||||||
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
|
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -568,7 +568,7 @@ struct InsTrim : public ModulePass {
|
|||||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
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);
|
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) {
|
void MakeUniq(uint32_t now) {
|
||||||
|
|
||||||
bool StopFlag = false;
|
|
||||||
if (Marked.find(now) == Marked.end()) {
|
if (Marked.find(now) == Marked.end()) {
|
||||||
|
|
||||||
for (uint32_t pred1 : t_Pred[now]) {
|
for (uint32_t pred1 : t_Pred[now]) {
|
||||||
|
|
||||||
|
bool StopFlag = false;
|
||||||
for (uint32_t pred2 : t_Pred[now]) {
|
for (uint32_t pred2 : t_Pred[now]) {
|
||||||
|
|
||||||
if (pred1 == pred2) continue;
|
if (pred1 == pred2) continue;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# Using afl++ with partial instrumentation
|
# Using afl++ with partial instrumentation
|
||||||
|
|
||||||
This file describes how to selectively instrument only source files
|
This file describes two different mechanisms to selectively instrument
|
||||||
or functions that are of interest to you using the LLVM and GCC_PLUGIN
|
only specific parts in the target.
|
||||||
instrumentation provided by afl++.
|
|
||||||
|
Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc.
|
||||||
|
|
||||||
## 1) Description and purpose
|
## 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
|
on the important parts of the program, avoiding undesired noise and
|
||||||
disturbance by uninteresting code being exercised.
|
disturbance by uninteresting code being exercised.
|
||||||
|
|
||||||
For this purpose, a "partial instrumentation" support en par with llvm sancov
|
For this purpose, "partial instrumentation" support is provided by afl++ that
|
||||||
is provided by afl++ that allows to specify on a source file and function
|
allows to specify what should be instrumented and what not.
|
||||||
level which function should be compiled with or without instrumentation.
|
|
||||||
|
|
||||||
Note: When using PCGUARD mode - and llvm 12+ - you can use this instead:
|
Both mechanisms can be used together.
|
||||||
https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
|
|
||||||
|
|
||||||
The llvm sancov list format is fully supported by afl++, however afl++ has
|
## 2) Selective instrumentation with __AFL_COVERAGE_... directives
|
||||||
more flexibility.
|
|
||||||
|
|
||||||
## 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/
|
After the includes a special define has to be made, eg.:
|
||||||
subdirectory. There is nothing specifically to do for the build :)
|
|
||||||
|
|
||||||
## 2b) Building the GCC module
|
```
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
// ...
|
||||||
|
|
||||||
The new code is part of the existing afl++ GCC_PLUGIN module in the
|
__AFL_COVERAGE(); // <- required for this feature to work
|
||||||
instrumentation/ subdirectory. There is nothing specifically to do for
|
```
|
||||||
the build :)
|
|
||||||
|
|
||||||
## 3) How to use the partial instrumentation mode
|
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.
|
||||||
|
|
||||||
|
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
|
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++.
|
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.
|
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.
|
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.
|
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
|
Please see [README.persistent_mode.md](README.persistent_mode.md) for a
|
||||||
full explanation.
|
full explanation.
|
||||||
|
|
||||||
## 7) Bonus feature: 'trace-pc-guard' mode
|
## 7) Bonus feature: 'dict2file' pass
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation
|
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
|
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 yourself (version 12)
|
||||||
|
|
||||||
Building llvm from github takes quite some long time and is not painless:
|
Building llvm from github takes quite some long time and is not painless:
|
||||||
```
|
```sh
|
||||||
sudo apt install binutils-dev # this is *essential*!
|
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
|
cd llvm-project
|
||||||
mkdir build
|
mkdir build
|
||||||
cd 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)
|
# Add -G Ninja if ninja-build installed
|
||||||
export PATH=`pwd`/bin:$PATH
|
# "Building with ninja significantly improves your build time, especially with
|
||||||
export LLVM_CONFIG=`pwd`/bin/llvm-config
|
# 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/
|
cd /path/to/AFLplusplus/
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
@ -760,7 +760,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
|||||||
if (literalLength + 1 == optLength) {
|
if (literalLength + 1 == optLength) {
|
||||||
|
|
||||||
Str2.append("\0", 1); // add null byte
|
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_CFISAN") ? ", CFISAN" : "",
|
||||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||||
OKF("Instrumented %u locations with no collisions (on average %llu "
|
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);
|
inst, calculateCollisions(inst), modeline);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1237,6 +1237,25 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
|||||||
|
|
||||||
for (auto &BB : F) {
|
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))
|
if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
|
||||||
BlocksToInstrument.push_back(&BB);
|
BlocksToInstrument.push_back(&BB);
|
||||||
for (auto &Inst : BB) {
|
for (auto &Inst : BB) {
|
||||||
@ -1338,6 +1357,7 @@ bool ModuleSanitizerCoverage::InjectCoverage(Function & F,
|
|||||||
|
|
||||||
if (AllBlocks.empty()) return false;
|
if (AllBlocks.empty()) return false;
|
||||||
CreateFunctionLocalArrays(F, AllBlocks);
|
CreateFunctionLocalArrays(F, AllBlocks);
|
||||||
|
|
||||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||||
|
|
||||||
// afl++ START
|
// afl++ START
|
||||||
@ -1403,24 +1423,17 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
|
|||||||
|
|
||||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
bool IsEntryBB = &BB == &F.getEntryBlock();
|
bool IsEntryBB = &BB == &F.getEntryBlock();
|
||||||
DebugLoc EntryLoc;
|
|
||||||
if (IsEntryBB) {
|
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
|
// 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
|
// if we aren't splitting the block, it's nice for allocas to be before
|
||||||
// calls.
|
// calls.
|
||||||
IP = PrepareToSplitEntryBlock(BB, IP);
|
IP = PrepareToSplitEntryBlock(BB, IP);
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
EntryLoc = IP->getDebugLoc();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IRBuilder<> IRB(&*IP);
|
IRBuilder<> IRB(&*IP);
|
||||||
IRB.SetCurrentDebugLocation(EntryLoc);
|
|
||||||
if (Options.TracePC) {
|
if (Options.TracePC) {
|
||||||
|
|
||||||
IRB.CreateCall(SanCovTracePC)
|
IRB.CreateCall(SanCovTracePC)
|
||||||
|
@ -311,7 +311,8 @@ class ModuleSanitizerCoverage {
|
|||||||
Function &F, Type *Ty,
|
Function &F, Type *Ty,
|
||||||
const char *Section);
|
const char *Section);
|
||||||
GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
|
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,
|
void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
|
||||||
bool IsLeafFunc = true);
|
bool IsLeafFunc = true);
|
||||||
Function *CreateInitCallsForSections(Module &M, const char *CtorName,
|
Function *CreateInitCallsForSections(Module &M, const char *CtorName,
|
||||||
@ -970,11 +971,11 @@ GlobalVariable *ModuleSanitizerCoverage::CreatePCArray(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleSanitizerCoverage::CreateFunctionLocalArrays(
|
void ModuleSanitizerCoverage::CreateFunctionLocalArrays(
|
||||||
Function &F, ArrayRef<BasicBlock *> AllBlocks) {
|
Function &F, ArrayRef<BasicBlock *> AllBlocks, uint32_t special) {
|
||||||
|
|
||||||
if (Options.TracePCGuard)
|
if (Options.TracePCGuard)
|
||||||
FunctionGuardArray = CreateFunctionLocalArrayInSection(
|
FunctionGuardArray = CreateFunctionLocalArrayInSection(
|
||||||
AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName);
|
AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName);
|
||||||
|
|
||||||
if (Options.Inline8bitCounters)
|
if (Options.Inline8bitCounters)
|
||||||
Function8bitCounterArray = CreateFunctionLocalArrayInSection(
|
Function8bitCounterArray = CreateFunctionLocalArrayInSection(
|
||||||
@ -993,9 +994,38 @@ bool ModuleSanitizerCoverage::InjectCoverage(Function & F,
|
|||||||
bool IsLeafFunc) {
|
bool IsLeafFunc) {
|
||||||
|
|
||||||
if (AllBlocks.empty()) return false;
|
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++)
|
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||||
|
|
||||||
|
instr += special;
|
||||||
|
|
||||||
return true;
|
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) {
|
[](const Constant *A, const Constant *B) {
|
||||||
|
|
||||||
return cast<ConstantInt>(A)->getLimitedValue() <
|
return cast<ConstantInt>(A)->getLimitedValue() <
|
||||||
@ -1106,10 +1136,10 @@ void ModuleSanitizerCoverage::InjectTraceForGep(
|
|||||||
for (auto GEP : GepTraceTargets) {
|
for (auto GEP : GepTraceTargets) {
|
||||||
|
|
||||||
IRBuilder<> IRB(GEP);
|
IRBuilder<> IRB(GEP);
|
||||||
for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
|
for (Use &Idx : GEP->indices())
|
||||||
if (!isa<ConstantInt>(*I) && (*I)->getType()->isIntegerTy())
|
if (!isa<ConstantInt>(Idx) && Idx->getType()->isIntegerTy())
|
||||||
IRB.CreateCall(SanCovTraceGepFunction,
|
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();
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
bool IsEntryBB = &BB == &F.getEntryBlock();
|
bool IsEntryBB = &BB == &F.getEntryBlock();
|
||||||
DebugLoc EntryLoc;
|
|
||||||
if (IsEntryBB) {
|
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
|
// 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
|
// if we aren't splitting the block, it's nice for allocas to be before
|
||||||
// calls.
|
// calls.
|
||||||
IP = PrepareToSplitEntryBlock(BB, IP);
|
IP = PrepareToSplitEntryBlock(BB, IP);
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
EntryLoc = IP->getDebugLoc();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IRBuilder<> IRB(&*IP);
|
IRBuilder<> IRB(&*IP);
|
||||||
IRB.SetCurrentDebugLocation(EntryLoc);
|
|
||||||
if (Options.TracePC) {
|
if (Options.TracePC) {
|
||||||
|
|
||||||
IRB.CreateCall(SanCovTracePC);
|
IRB.CreateCall(SanCovTracePC);
|
||||||
|
@ -70,13 +70,15 @@
|
|||||||
run. It will end up as .comm, so it shouldn't be too wasteful. */
|
run. It will end up as .comm, so it shouldn't be too wasteful. */
|
||||||
|
|
||||||
#if MAP_SIZE <= 65536
|
#if MAP_SIZE <= 65536
|
||||||
#define MAP_INITIAL_SIZE 256000
|
#define MAP_INITIAL_SIZE 2097152
|
||||||
#else
|
#else
|
||||||
#define MAP_INITIAL_SIZE MAP_SIZE
|
#define MAP_INITIAL_SIZE MAP_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
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 = __afl_area_initial;
|
||||||
|
u8 * __afl_area_ptr_backup = __afl_area_initial;
|
||||||
u8 * __afl_dictionary;
|
u8 * __afl_dictionary;
|
||||||
u8 * __afl_fuzz_ptr;
|
u8 * __afl_fuzz_ptr;
|
||||||
u32 __afl_fuzz_len_dummy;
|
u32 __afl_fuzz_len_dummy;
|
||||||
@ -87,7 +89,12 @@ u32 __afl_map_size = MAP_SIZE;
|
|||||||
u32 __afl_dictionary_len;
|
u32 __afl_dictionary_len;
|
||||||
u64 __afl_map_addr;
|
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];
|
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||||
u32 __afl_prev_ctx;
|
u32 __afl_prev_ctx;
|
||||||
u32 __afl_cmp_counter;
|
u32 __afl_cmp_counter;
|
||||||
@ -100,6 +107,7 @@ __thread u32 __afl_cmp_counter;
|
|||||||
int __afl_sharedmem_fuzzing __attribute__((weak));
|
int __afl_sharedmem_fuzzing __attribute__((weak));
|
||||||
|
|
||||||
struct cmp_map *__afl_cmp_map;
|
struct cmp_map *__afl_cmp_map;
|
||||||
|
struct cmp_map *__afl_cmp_map_backup;
|
||||||
|
|
||||||
/* Child pid? */
|
/* Child pid? */
|
||||||
|
|
||||||
@ -153,7 +161,7 @@ void send_forkserver_error(int error) {
|
|||||||
u32 status;
|
u32 status;
|
||||||
if (!error || error > 0xffff) return;
|
if (!error || error > 0xffff) return;
|
||||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
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) {
|
static void __afl_map_shm(void) {
|
||||||
|
|
||||||
// if we are not running in afl ensure the map exists
|
// 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);
|
char *id_str = getenv(SHM_ENV_VAR);
|
||||||
|
|
||||||
if (__afl_final_loc) {
|
if (__afl_final_loc) {
|
||||||
|
|
||||||
if (__afl_final_loc % 8)
|
if (__afl_final_loc % 64) {
|
||||||
__afl_final_loc = (((__afl_final_loc + 7) >> 3) << 3);
|
|
||||||
|
__afl_final_loc = (((__afl_final_loc + 63) >> 6) << 6);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
__afl_map_size = __afl_final_loc;
|
__afl_map_size = __afl_final_loc;
|
||||||
|
|
||||||
if (__afl_final_loc > MAP_SIZE) {
|
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_area_ptr && __afl_area_ptr != __afl_area_initial) {
|
||||||
|
|
||||||
if (__afl_map_addr)
|
if (__afl_map_addr) {
|
||||||
|
|
||||||
munmap((void *)__afl_map_addr, __afl_final_loc);
|
munmap((void *)__afl_map_addr, __afl_final_loc);
|
||||||
else
|
|
||||||
|
} else {
|
||||||
|
|
||||||
free(__afl_area_ptr);
|
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
|
#else
|
||||||
u32 shm_id = atoi(id_str);
|
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. */
|
/* Whooooops. */
|
||||||
|
|
||||||
@ -379,8 +409,8 @@ static void __afl_map_shm(void) {
|
|||||||
|
|
||||||
__afl_map_addr) {
|
__afl_map_addr) {
|
||||||
|
|
||||||
__afl_area_ptr =
|
__afl_area_ptr = (u8 *)mmap(
|
||||||
mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
|
(void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
|
||||||
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
|
|
||||||
if (__afl_area_ptr == MAP_FAILED) {
|
if (__afl_area_ptr == MAP_FAILED) {
|
||||||
@ -396,9 +426,42 @@ static void __afl_map_shm(void) {
|
|||||||
|
|
||||||
free(__afl_area_ptr);
|
free(__afl_area_ptr);
|
||||||
__afl_area_ptr = NULL;
|
__afl_area_ptr = NULL;
|
||||||
if (__afl_final_loc > MAP_INITIAL_SIZE)
|
|
||||||
__afl_area_ptr = malloc(__afl_final_loc);
|
if (__afl_final_loc > MAP_INITIAL_SIZE) {
|
||||||
if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
|
|
||||||
|
__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
|
#else
|
||||||
u32 shm_id = atoi(id_str);
|
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
|
#endif
|
||||||
|
|
||||||
|
__afl_cmp_map_backup = __afl_cmp_map;
|
||||||
|
|
||||||
if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) {
|
if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) {
|
||||||
|
|
||||||
perror("shmat for cmplog");
|
perror("shmat for cmplog");
|
||||||
@ -483,11 +548,11 @@ static void __afl_start_snapshots(void) {
|
|||||||
if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
|
if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
|
||||||
memcpy(tmp, &status, 4);
|
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 (__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")) {
|
if (getenv("AFL_DEBUG")) {
|
||||||
|
|
||||||
@ -683,7 +748,7 @@ static void __afl_start_forkserver(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
u8 tmp[4] = {0, 0, 0, 0};
|
u8 tmp[4] = {0, 0, 0, 0};
|
||||||
u32 status = 0;
|
u32 status_for_fsrv = 0;
|
||||||
u32 already_read_first = 0;
|
u32 already_read_first = 0;
|
||||||
u32 was_killed;
|
u32 was_killed;
|
||||||
|
|
||||||
@ -691,17 +756,26 @@ static void __afl_start_forkserver(void) {
|
|||||||
|
|
||||||
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
|
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
|
||||||
|
|
||||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
|
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;
|
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||||
if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
|
|
||||||
if (status) status |= (FS_OPT_ENABLED);
|
}
|
||||||
memcpy(tmp, &status, 4);
|
|
||||||
|
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,
|
/* 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. */
|
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)) {
|
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
|
// great lets pass the dictionary through the forkserver FD
|
||||||
u32 len = __afl_dictionary_len, offset = 0;
|
u32 len = __afl_dictionary_len, offset = 0;
|
||||||
s32 ret;
|
|
||||||
|
|
||||||
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
||||||
|
|
||||||
@ -738,6 +811,7 @@ static void __afl_start_forkserver(void) {
|
|||||||
|
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
|
|
||||||
|
s32 ret;
|
||||||
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
|
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
|
||||||
|
|
||||||
if (ret < 1) {
|
if (ret < 1) {
|
||||||
@ -894,6 +968,8 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
|||||||
|
|
||||||
cycle_cnt = max_cnt;
|
cycle_cnt = max_cnt;
|
||||||
first_pass = 0;
|
first_pass = 0;
|
||||||
|
__afl_selective_coverage_temp = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -906,6 +982,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
|
|||||||
|
|
||||||
__afl_area_ptr[0] = 1;
|
__afl_area_ptr[0] = 1;
|
||||||
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
|
||||||
|
__afl_selective_coverage_temp = 1;
|
||||||
|
|
||||||
return 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
|
follows the loop is not traced. We do that by pivoting back to the
|
||||||
dummy output region. */
|
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;
|
init_done = 1;
|
||||||
is_persistent = 0;
|
is_persistent = 0;
|
||||||
__afl_sharedmem_fuzzing = 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"))
|
if (getenv("AFL_DEBUG"))
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -998,7 +1075,12 @@ __attribute__((constructor(1))) void __afl_auto_second(void) {
|
|||||||
else
|
else
|
||||||
ptr = (u8 *)malloc(__afl_final_loc);
|
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;
|
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||||
u8 *ptr;
|
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")) {
|
if (getenv("AFL_DEBUG")) {
|
||||||
|
|
||||||
fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
|
fprintf(stderr,
|
||||||
start, stop);
|
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n",
|
||||||
|
start, stop, (unsigned long)(stop - start));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1124,72 +1212,207 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
|||||||
|
|
||||||
///// CmpLog instrumentation
|
///// 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);
|
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
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;
|
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
||||||
|
hits = 0;
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
__afl_cmp_map->headers[k].hits = 1;
|
||||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
|
||||||
// if (!__afl_cmp_map->headers[k].cnt)
|
|
||||||
// __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
|
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].shape = 0;
|
__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;
|
hits &= CMP_MAP_H - 1;
|
||||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||||
__afl_cmp_map->log[k][hits].v1 = arg2;
|
__afl_cmp_map->log[k][hits].v1 = 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);
|
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
k &= CMP_MAP_W - 1;
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
u32 hits;
|
||||||
|
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||||
__afl_cmp_map->headers[k].hits = hits + 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].shape = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
__afl_cmp_map->headers[k].attribute = attr;
|
||||||
|
|
||||||
hits &= CMP_MAP_H - 1;
|
hits &= CMP_MAP_H - 1;
|
||||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||||
__afl_cmp_map->log[k][hits].v1 = arg2;
|
__afl_cmp_map->log[k][hits].v1 = 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);
|
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
k &= CMP_MAP_W - 1;
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
u32 hits;
|
||||||
|
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||||
__afl_cmp_map->headers[k].hits = hits + 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 = 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].shape = 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
__afl_cmp_map->headers[k].attribute = attr;
|
||||||
|
|
||||||
hits &= CMP_MAP_H - 1;
|
hits &= CMP_MAP_H - 1;
|
||||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
__afl_cmp_map->log[k][hits].v0 = arg1;
|
||||||
__afl_cmp_map->log[k][hits].v1 = arg2;
|
__afl_cmp_map->log[k][hits].v1 = arg2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
|
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) {
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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 = 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;
|
||||||
|
__afl_cmp_map->log[k][hits].v1 = arg2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#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) {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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;
|
if (unlikely(!__afl_cmp_map)) return;
|
||||||
|
|
||||||
@ -1197,48 +1420,95 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
|
|||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
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;
|
__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;
|
||||||
|
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
} else {
|
||||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].shape = 7;
|
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;
|
hits &= CMP_MAP_H - 1;
|
||||||
__afl_cmp_map->log[k][hits].v0 = arg1;
|
__afl_cmp_map->log[k][hits].v0 = (u64)arg1;
|
||||||
__afl_cmp_map->log[k][hits].v1 = arg2;
|
__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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#endif
|
||||||
#pragma weak __sanitizer_cov_trace_const_cmp1 = __cmplog_ins_hook1
|
|
||||||
#pragma weak __sanitizer_cov_trace_const_cmp2 = __cmplog_ins_hook2
|
|
||||||
#pragma weak __sanitizer_cov_trace_const_cmp4 = __cmplog_ins_hook4
|
|
||||||
#pragma weak __sanitizer_cov_trace_const_cmp8 = __cmplog_ins_hook8
|
|
||||||
|
|
||||||
#pragma weak __sanitizer_cov_trace_cmp1 = __cmplog_ins_hook1
|
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
|
||||||
#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")));
|
|
||||||
|
|
||||||
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
|
__cmplog_ins_hook1(arg1, arg2, 0);
|
||||||
__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)
|
void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) {
|
||||||
__attribute__((alias("__cmplog_ins_hook4")));
|
|
||||||
void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
|
__cmplog_ins_hook1(arg1, arg2, 0);
|
||||||
__attribute__((alias("__cmplog_ins_hook8")));
|
|
||||||
#endif /* defined(__APPLE__) */
|
}
|
||||||
|
|
||||||
|
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) {
|
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||||
|
|
||||||
@ -1250,13 +1520,29 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
|||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
k &= CMP_MAP_W - 1;
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
|
u32 hits;
|
||||||
|
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS) {
|
||||||
__afl_cmp_map->headers[k].hits = hits + 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 = 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].shape = 7;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
__afl_cmp_map->headers[k].attribute = 1;
|
||||||
|
|
||||||
hits &= CMP_MAP_H - 1;
|
hits &= CMP_MAP_H - 1;
|
||||||
__afl_cmp_map->log[k][hits].v0 = val;
|
__afl_cmp_map->log[k][hits].v0 = val;
|
||||||
__afl_cmp_map->log[k][hits].v1 = cases[i + 2];
|
__afl_cmp_map->log[k][hits].v1 = cases[i + 2];
|
||||||
@ -1270,7 +1556,7 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
|||||||
// to avoid to call it on .text addresses
|
// to avoid to call it on .text addresses
|
||||||
static int area_is_mapped(void *ptr, size_t len) {
|
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));
|
char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1));
|
||||||
|
|
||||||
int r = msync(page, (p - page) + len, MS_ASYNC);
|
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) {
|
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 (unlikely(!__afl_cmp_map)) return;
|
||||||
|
|
||||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||||
@ -1289,13 +1587,27 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
|||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMP_MAP_W - 1;
|
k &= CMP_MAP_W - 1;
|
||||||
|
|
||||||
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
|
u32 hits;
|
||||||
|
|
||||||
u32 hits = __afl_cmp_map->headers[k].hits;
|
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
|
||||||
__afl_cmp_map->headers[k].hits = hits + 1;
|
|
||||||
|
__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;
|
__afl_cmp_map->headers[k].shape = 31;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
hits &= CMP_MAP_RTN_H - 1;
|
hits &= CMP_MAP_RTN_H - 1;
|
||||||
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
|
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
|
||||||
ptr1, 32);
|
ptr1, 32);
|
||||||
@ -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;
|
const bool neverZero;
|
||||||
|
|
||||||
/* Count instrumented blocks. */
|
/* Count instrumented blocks. */
|
||||||
int inst_blocks;
|
unsigned int inst_blocks;
|
||||||
|
|
||||||
virtual unsigned int execute(function *fn) {
|
virtual unsigned int execute(function *fn) {
|
||||||
|
|
||||||
@ -444,8 +444,10 @@ struct afl_pass : gimple_opt_pass {
|
|||||||
DECL_EXTERNAL(decl) = 1;
|
DECL_EXTERNAL(decl) = 1;
|
||||||
DECL_ARTIFICIAL(decl) = 1;
|
DECL_ARTIFICIAL(decl) = 1;
|
||||||
TREE_STATIC(decl) = 1;
|
TREE_STATIC(decl) = 1;
|
||||||
|
#if !defined(__ANDROID__) && !defined(__HAIKU__)
|
||||||
set_decl_tls_model(
|
set_decl_tls_model(
|
||||||
decl, (flag_pic ? TLS_MODEL_INITIAL_EXEC : TLS_MODEL_LOCAL_EXEC));
|
decl, (flag_pic ? TLS_MODEL_INITIAL_EXEC : TLS_MODEL_LOCAL_EXEC));
|
||||||
|
#endif
|
||||||
return decl;
|
return decl;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -516,7 +518,9 @@ struct afl_pass : gimple_opt_pass {
|
|||||||
"__cmplog",
|
"__cmplog",
|
||||||
"__sancov",
|
"__sancov",
|
||||||
"msan.",
|
"msan.",
|
||||||
"LLVMFuzzer",
|
"LLVMFuzzerM",
|
||||||
|
"LLVMFuzzerC",
|
||||||
|
"LLVMFuzzerI",
|
||||||
"__decide_deferred",
|
"__decide_deferred",
|
||||||
"maybe_duplicate_stderr",
|
"maybe_duplicate_stderr",
|
||||||
"discard_output",
|
"discard_output",
|
||||||
@ -620,10 +624,11 @@ struct afl_pass : gimple_opt_pass {
|
|||||||
allowListFiles.push_back(line);
|
allowListFiles.push_back(line);
|
||||||
else
|
else
|
||||||
allowListFunctions.push_back(line);
|
allowListFunctions.push_back(line);
|
||||||
getline(fileStream, line);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -694,10 +699,11 @@ struct afl_pass : gimple_opt_pass {
|
|||||||
denyListFiles.push_back(line);
|
denyListFiles.push_back(line);
|
||||||
else
|
else
|
||||||
denyListFunctions.push_back(line);
|
denyListFunctions.push_back(line);
|
||||||
getline(fileStream, line);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -916,8 +922,9 @@ int plugin_init(struct plugin_name_args * info,
|
|||||||
struct plugin_gcc_version *version) {
|
struct plugin_gcc_version *version) {
|
||||||
|
|
||||||
if (!plugin_default_version_check(version, &gcc_version))
|
if (!plugin_default_version_check(version, &gcc_version))
|
||||||
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %d.%d"),
|
FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
|
||||||
GCCPLUGIN_VERSION_MAJOR, GCCPLUGIN_VERSION_MINOR);
|
"is %s"),
|
||||||
|
gcc_version.basever, version->basever);
|
||||||
|
|
||||||
/* Show a banner. */
|
/* Show a banner. */
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
@ -927,7 +934,7 @@ int plugin_init(struct plugin_name_args * info,
|
|||||||
quiet = true;
|
quiet = true;
|
||||||
|
|
||||||
/* Decide instrumentation ratio. */
|
/* Decide instrumentation ratio. */
|
||||||
int inst_ratio = 100;
|
unsigned int inst_ratio = 100U;
|
||||||
if (char *inst_ratio_str = getenv("AFL_INST_RATIO"))
|
if (char *inst_ratio_str = getenv("AFL_INST_RATIO"))
|
||||||
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
|
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
|
||||||
inst_ratio > 100)
|
inst_ratio > 100)
|
||||||
|
@ -70,7 +70,9 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
|||||||
"__cmplog",
|
"__cmplog",
|
||||||
"__sancov",
|
"__sancov",
|
||||||
"msan.",
|
"msan.",
|
||||||
"LLVMFuzzer",
|
"LLVMFuzzerM",
|
||||||
|
"LLVMFuzzerC",
|
||||||
|
"LLVMFuzzerI",
|
||||||
"__decide_deferred",
|
"__decide_deferred",
|
||||||
"maybe_duplicate_stderr",
|
"maybe_duplicate_stderr",
|
||||||
"discard_output",
|
"discard_output",
|
||||||
@ -166,10 +168,11 @@ void initInstrumentList() {
|
|||||||
allowListFiles.push_back(line);
|
allowListFiles.push_back(line);
|
||||||
else
|
else
|
||||||
allowListFunctions.push_back(line);
|
allowListFunctions.push_back(line);
|
||||||
getline(fileStream, line);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -240,10 +243,11 @@ void initInstrumentList() {
|
|||||||
denyListFiles.push_back(line);
|
denyListFiles.push_back(line);
|
||||||
else
|
else
|
||||||
denyListFunctions.push_back(line);
|
denyListFunctions.push_back(line);
|
||||||
getline(fileStream, line);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -347,7 +351,7 @@ static std::string getSourceName(llvm::Function *F) {
|
|||||||
|
|
||||||
if (cDILoc) { instFilename = cDILoc->getFilename(); }
|
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
|
/* 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;
|
j = 1;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
|
||||||
if (isprint(mem[i])) {
|
if (isprint(mem[i]) && mem[i] != '\\' && mem[i] != '"') {
|
||||||
|
|
||||||
line[j++] = mem[i];
|
line[j++] = mem[i];
|
||||||
|
|
||||||
@ -355,7 +355,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
|||||||
*Str2P = callInst->getArgOperand(1);
|
*Str2P = callInst->getArgOperand(1);
|
||||||
std::string Str1, Str2;
|
std::string Str1, Str2;
|
||||||
StringRef TmpStr;
|
StringRef TmpStr;
|
||||||
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
|
bool HasStr1;
|
||||||
|
getConstantStringInfo(Str1P, TmpStr);
|
||||||
if (TmpStr.empty()) {
|
if (TmpStr.empty()) {
|
||||||
|
|
||||||
HasStr1 = false;
|
HasStr1 = false;
|
||||||
@ -367,7 +368,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
|
bool HasStr2;
|
||||||
|
getConstantStringInfo(Str2P, TmpStr);
|
||||||
if (TmpStr.empty()) {
|
if (TmpStr.empty()) {
|
||||||
|
|
||||||
HasStr2 = false;
|
HasStr2 = false;
|
||||||
@ -428,7 +430,6 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
|||||||
if (literalLength + 1 == optLength) {
|
if (literalLength + 1 == optLength) {
|
||||||
|
|
||||||
Str2.append("\0", 1); // add null byte
|
Str2.append("\0", 1); // add null byte
|
||||||
addedNull = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +69,9 @@ class AFLLTOPass : public ModulePass {
|
|||||||
|
|
||||||
if (getenv("AFL_DEBUG")) debug = 1;
|
if (getenv("AFL_DEBUG")) debug = 1;
|
||||||
if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
|
if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
|
||||||
if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE)
|
if ((afl_global_id = (uint32_t)atoi(ptr)) < 0 ||
|
||||||
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
|
afl_global_id >= MAP_SIZE)
|
||||||
|
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %u\n",
|
||||||
ptr, MAP_SIZE - 1);
|
ptr, MAP_SIZE - 1);
|
||||||
|
|
||||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||||
@ -88,7 +89,7 @@ class AFLLTOPass : public ModulePass {
|
|||||||
bool runOnModule(Module &M) override;
|
bool runOnModule(Module &M) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int afl_global_id = 1, autodictionary = 1;
|
uint32_t afl_global_id = 1, autodictionary = 1;
|
||||||
uint32_t function_minimum_size = 1;
|
uint32_t function_minimum_size = 1;
|
||||||
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
|
||||||
uint64_t map_addr = 0x10000;
|
uint64_t map_addr = 0x10000;
|
||||||
@ -102,7 +103,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
LLVMContext & C = M.getContext();
|
LLVMContext & C = M.getContext();
|
||||||
std::vector<std::string> dictionary;
|
std::vector<std::string> dictionary;
|
||||||
std::vector<CallInst *> calls;
|
// std::vector<CallInst *> calls;
|
||||||
DenseMap<Value *, std::string *> valueMap;
|
DenseMap<Value *, std::string *> valueMap;
|
||||||
std::vector<BasicBlock *> BlockList;
|
std::vector<BasicBlock *> BlockList;
|
||||||
char * ptr;
|
char * ptr;
|
||||||
@ -471,7 +472,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
*Str2P = callInst->getArgOperand(1);
|
*Str2P = callInst->getArgOperand(1);
|
||||||
std::string Str1, Str2;
|
std::string Str1, Str2;
|
||||||
StringRef TmpStr;
|
StringRef TmpStr;
|
||||||
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
|
bool HasStr1;
|
||||||
|
getConstantStringInfo(Str1P, TmpStr);
|
||||||
if (TmpStr.empty()) {
|
if (TmpStr.empty()) {
|
||||||
|
|
||||||
HasStr1 = false;
|
HasStr1 = false;
|
||||||
@ -483,7 +485,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
|
bool HasStr2;
|
||||||
|
getConstantStringInfo(Str2P, TmpStr);
|
||||||
if (TmpStr.empty()) {
|
if (TmpStr.empty()) {
|
||||||
|
|
||||||
HasStr2 = false;
|
HasStr2 = false;
|
||||||
@ -543,7 +546,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
if (literalLength + 1 == optLength) {
|
if (literalLength + 1 == optLength) {
|
||||||
|
|
||||||
Str2.append("\0", 1); // add null byte
|
Str2.append("\0", 1); // add null byte
|
||||||
addedNull = true;
|
// addedNull = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,7 +674,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
if (!be_quiet) {
|
if (!be_quiet) {
|
||||||
|
|
||||||
std::string outstring;
|
|
||||||
fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
|
fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
|
||||||
thestring.length());
|
thestring.length());
|
||||||
for (uint8_t i = 0; i < thestring.length(); i++) {
|
for (uint8_t i = 0; i < thestring.length(); i++) {
|
||||||
@ -872,7 +874,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
pow2map++;
|
pow2map++;
|
||||||
WARNF(
|
WARNF(
|
||||||
"We have %u blocks to instrument but the map size is only %u. Either "
|
"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-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 "
|
"AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
|
||||||
"target.",
|
"target.",
|
||||||
@ -922,9 +924,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
|
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
|
||||||
|
|
||||||
uint32_t write_loc = afl_global_id;
|
uint32_t write_loc = (((afl_global_id + 63) >> 6) << 6);
|
||||||
|
|
||||||
if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
|
|
||||||
|
|
||||||
GlobalVariable *AFLFinalLoc = new GlobalVariable(
|
GlobalVariable *AFLFinalLoc = new GlobalVariable(
|
||||||
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc");
|
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc");
|
||||||
@ -937,8 +937,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
if (dictionary.size()) {
|
if (dictionary.size()) {
|
||||||
|
|
||||||
size_t memlen = 0, count = 0, offset = 0;
|
size_t memlen = 0, count = 0;
|
||||||
char * ptr;
|
|
||||||
|
|
||||||
// sort and unique the dictionary
|
// sort and unique the dictionary
|
||||||
std::sort(dictionary.begin(), dictionary.end());
|
std::sort(dictionary.begin(), dictionary.end());
|
||||||
@ -953,14 +952,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!be_quiet)
|
if (!be_quiet)
|
||||||
printf("AUTODICTIONARY: %lu string%s found\n", count,
|
printf("AUTODICTIONARY: %zu string%s found\n", count,
|
||||||
count == 1 ? "" : "s");
|
count == 1 ? "" : "s");
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
|
|
||||||
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
|
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);
|
memlen + count);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
@ -968,6 +967,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
|
|||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
for (auto token : dictionary) {
|
for (auto token : dictionary) {
|
||||||
|
|
||||||
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
|
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_MSAN") ? ", MSAN" : "",
|
||||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||||
OKF("Instrumented %u locations with no collisions (on average %llu "
|
OKF("Instrumented %d 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_blocks, calculateCollisions(inst_blocks), modeline);
|
inst_blocks, calculateCollisions(inst_blocks), modeline);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
GlobalVariable *AFLContext = NULL;
|
GlobalVariable *AFLContext = NULL;
|
||||||
|
|
||||||
if (ctx_str)
|
if (ctx_str)
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLContext = new GlobalVariable(
|
AFLContext = new GlobalVariable(
|
||||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||||
#else
|
#else
|
||||||
@ -252,7 +252,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
|
|
||||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||||
if (ngram_size)
|
if (ngram_size)
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLPrevLoc = new GlobalVariable(
|
AFLPrevLoc = new GlobalVariable(
|
||||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||||
@ -265,7 +265,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef __ANDROID__
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
AFLPrevLoc = new GlobalVariable(
|
AFLPrevLoc = new GlobalVariable(
|
||||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||||
#else
|
#else
|
||||||
@ -327,10 +327,10 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
|
|
||||||
// does the function have calls? and is any of the calls larger than one
|
// does the function have calls? and is any of the calls larger than one
|
||||||
// basic block?
|
// basic block?
|
||||||
for (auto &BB : F) {
|
for (auto &BB_2 : F) {
|
||||||
|
|
||||||
if (has_calls) break;
|
if (has_calls) break;
|
||||||
for (auto &IN : BB) {
|
for (auto &IN : BB_2) {
|
||||||
|
|
||||||
CallInst *callInst = nullptr;
|
CallInst *callInst = nullptr;
|
||||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||||
@ -538,6 +538,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
|
|
||||||
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
|
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
|
||||||
AFLPrevLoc);
|
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_MSAN") ? ", MSAN" : "",
|
||||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
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);
|
modeline, inst_ratio);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "llvm/Config/llvm-config.h"
|
|
||||||
|
|
||||||
|
#include "llvm/Config/llvm-config.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
@ -85,9 +86,25 @@ class CmpLogInstructions : public ModulePass {
|
|||||||
|
|
||||||
char CmpLogInstructions::ID = 0;
|
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) {
|
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||||
|
|
||||||
std::vector<Instruction *> icomps;
|
std::vector<Instruction *> icomps;
|
||||||
|
std::vector<SwitchInst *> switches;
|
||||||
LLVMContext & C = M.getContext();
|
LLVMContext & C = M.getContext();
|
||||||
|
|
||||||
Type * VoidTy = Type::getVoidTy(C);
|
Type * VoidTy = Type::getVoidTy(C);
|
||||||
@ -95,13 +112,15 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
|
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
|
||||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||||
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||||
|
IntegerType *Int128Ty = IntegerType::getInt128Ty(C);
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR < 9
|
#if LLVM_VERSION_MAJOR < 9
|
||||||
Constant *
|
Constant *
|
||||||
#else
|
#else
|
||||||
FunctionCallee
|
FunctionCallee
|
||||||
#endif
|
#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
|
#if LLVM_VERSION_MAJOR < 5
|
||||||
,
|
,
|
||||||
NULL
|
NULL
|
||||||
@ -118,7 +137,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
#else
|
#else
|
||||||
FunctionCallee
|
FunctionCallee
|
||||||
#endif
|
#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
|
#if LLVM_VERSION_MAJOR < 5
|
||||||
,
|
,
|
||||||
NULL
|
NULL
|
||||||
@ -135,7 +155,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
#else
|
#else
|
||||||
FunctionCallee
|
FunctionCallee
|
||||||
#endif
|
#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
|
#if LLVM_VERSION_MAJOR < 5
|
||||||
,
|
,
|
||||||
NULL
|
NULL
|
||||||
@ -152,7 +173,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
#else
|
#else
|
||||||
FunctionCallee
|
FunctionCallee
|
||||||
#endif
|
#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
|
#if LLVM_VERSION_MAJOR < 5
|
||||||
,
|
,
|
||||||
NULL
|
NULL
|
||||||
@ -164,6 +186,42 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
FunctionCallee cmplogHookIns8 = c8;
|
FunctionCallee cmplogHookIns8 = c8;
|
||||||
#endif
|
#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 */
|
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
|
|
||||||
@ -174,33 +232,17 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
for (auto &IN : BB) {
|
for (auto &IN : BB) {
|
||||||
|
|
||||||
CmpInst *selectcmpInst = nullptr;
|
CmpInst *selectcmpInst = nullptr;
|
||||||
|
|
||||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||||
|
|
||||||
if (selectcmpInst->getPredicate() == CmpInst::ICMP_EQ ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_NE ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGT ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGT ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULT ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLT ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGE ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGE ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULE ||
|
|
||||||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) {
|
|
||||||
|
|
||||||
auto op0 = selectcmpInst->getOperand(0);
|
|
||||||
auto op1 = selectcmpInst->getOperand(1);
|
|
||||||
|
|
||||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
|
||||||
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
|
||||||
|
|
||||||
/* this is probably not needed but we do it anyway */
|
|
||||||
if (!intTyOp0 || !intTyOp1) { continue; }
|
|
||||||
|
|
||||||
icomps.push_back(selectcmpInst);
|
icomps.push_back(selectcmpInst);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwitchInst *switchInst = nullptr;
|
||||||
|
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
|
||||||
|
|
||||||
|
if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -209,30 +251,115 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!icomps.size()) return false;
|
// unique the collected switches
|
||||||
// if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp
|
switches.erase(Unique(switches.begin(), switches.end()), switches.end());
|
||||||
// instructions\n";
|
|
||||||
|
|
||||||
for (auto &selectcmpInst : icomps) {
|
// Instrument switch values for cmplog
|
||||||
|
if (switches.size()) {
|
||||||
|
|
||||||
IRBuilder<> IRB(selectcmpInst->getParent());
|
if (!be_quiet)
|
||||||
IRB.SetInsertPoint(selectcmpInst);
|
errs() << "Hooking " << switches.size() << " switch instructions\n";
|
||||||
|
|
||||||
auto op0 = selectcmpInst->getOperand(0);
|
for (auto &SI : switches) {
|
||||||
auto op1 = selectcmpInst->getOperand(1);
|
|
||||||
|
|
||||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
Value * Val = SI->getCondition();
|
||||||
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
|
unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size;
|
||||||
|
unsigned char do_cast = 0;
|
||||||
|
|
||||||
unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
|
if (!SI->getNumCases() || max_size < 16) {
|
||||||
? intTyOp0->getBitWidth()
|
|
||||||
: intTyOp1->getBitWidth();
|
// 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;
|
std::vector<Value *> args;
|
||||||
args.push_back(op0);
|
args.push_back(CompareTo);
|
||||||
args.push_back(op1);
|
|
||||||
|
|
||||||
switch (max_size) {
|
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:
|
case 8:
|
||||||
IRB.CreateCall(cmplogHookIns1, args);
|
IRB.CreateCall(cmplogHookIns1, args);
|
||||||
@ -246,6 +373,20 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
case 64:
|
case 64:
|
||||||
IRB.CreateCall(cmplogHookIns8, args);
|
IRB.CreateCall(cmplogHookIns8, args);
|
||||||
break;
|
break;
|
||||||
|
case 128:
|
||||||
|
#ifdef WORD_SIZE_64
|
||||||
|
if (max_size == 128) {
|
||||||
|
|
||||||
|
IRB.CreateCall(cmplogHookIns16, args);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
IRB.CreateCall(cmplogHookInsN, args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -253,7 +394,225 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icomps.size()) {
|
||||||
|
|
||||||
|
// if (!be_quiet) errs() << "Hooking " << icomps.size() <<
|
||||||
|
// " cmp instructions\n";
|
||||||
|
|
||||||
|
for (auto &selectcmpInst : icomps) {
|
||||||
|
|
||||||
|
IRBuilder<> IRB(selectcmpInst->getParent());
|
||||||
|
IRB.SetInsertPoint(selectcmpInst);
|
||||||
|
|
||||||
|
Value *op0 = selectcmpInst->getOperand(0);
|
||||||
|
Value *op1 = selectcmpInst->getOperand(1);
|
||||||
|
|
||||||
|
IntegerType * intTyOp0 = NULL;
|
||||||
|
IntegerType * intTyOp1 = NULL;
|
||||||
|
unsigned max_size = 0, cast_size = 0;
|
||||||
|
unsigned char attr = 0, do_cast = 0;
|
||||||
|
std::vector<Value *> args;
|
||||||
|
|
||||||
|
CmpInst *cmpInst = dyn_cast<CmpInst>(selectcmpInst);
|
||||||
|
|
||||||
|
if (!cmpInst) { continue; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switches.size() || icomps.size())
|
||||||
return true;
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ char CmpLogRoutines::ID = 0;
|
|||||||
|
|
||||||
bool CmpLogRoutines::hookRtns(Module &M) {
|
bool CmpLogRoutines::hookRtns(Module &M) {
|
||||||
|
|
||||||
std::vector<CallInst *> calls;
|
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC;
|
||||||
LLVMContext & C = M.getContext();
|
LLVMContext & C = M.getContext();
|
||||||
|
|
||||||
Type *VoidTy = Type::getVoidTy(C);
|
Type *VoidTy = Type::getVoidTy(C);
|
||||||
@ -112,6 +112,78 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
|||||||
FunctionCallee cmplogHookFn = c;
|
FunctionCallee cmplogHookFn = c;
|
||||||
#endif
|
#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 */
|
/* iterate over all functions, bbs and instruction and add suitable calls */
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
|
|
||||||
@ -136,9 +208,64 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
|||||||
FT->getParamType(0) == FT->getParamType(1) &&
|
FT->getParamType(0) == FT->getParamType(1) &&
|
||||||
FT->getParamType(0)->isPointerTy();
|
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)
|
if (!be_quiet)
|
||||||
errs() << "Hooking " << calls.size()
|
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;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
|
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
|
||||||
IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
|
IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 9
|
||||||
|
Function *tolowerFn;
|
||||||
|
#else
|
||||||
|
FunctionCallee tolowerFn;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR < 9
|
#if LLVM_VERSION_MAJOR < 9
|
||||||
Constant *
|
Constant *
|
||||||
#else
|
#else
|
||||||
@ -112,11 +119,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
#if LLVM_VERSION_MAJOR < 9
|
#if LLVM_VERSION_MAJOR < 9
|
||||||
Function *tolowerFn = cast<Function>(c);
|
tolowerFn = cast<Function>(c);
|
||||||
#else
|
#else
|
||||||
FunctionCallee tolowerFn = c;
|
tolowerFn = c;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* iterate over all functions, bbs and instruction and add suitable calls to
|
/* iterate over all functions, bbs and instruction and add suitable calls to
|
||||||
* strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
|
* strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
@ -234,7 +243,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
|
|
||||||
if (!HasStr2) {
|
if (!HasStr2) {
|
||||||
|
|
||||||
auto *Ptr = dyn_cast<ConstantExpr>(Str1P);
|
Ptr = dyn_cast<ConstantExpr>(Str1P);
|
||||||
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
|
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
|
||||||
|
|
||||||
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
|
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 HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||||
uint64_t constStrLen, unrollLen, constSizedLen = 0;
|
uint64_t constStrLen, unrollLen, constSizedLen = 0;
|
||||||
bool isMemcmp =
|
bool isMemcmp = false;
|
||||||
!callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
|
bool isSizedcmp = false;
|
||||||
bool isSizedcmp = isMemcmp ||
|
bool isCaseInsensitive = false;
|
||||||
!callInst->getCalledFunction()->getName().compare(
|
Function * Callee = callInst->getCalledFunction();
|
||||||
StringRef("strncmp")) ||
|
if (Callee) {
|
||||||
!callInst->getCalledFunction()->getName().compare(
|
|
||||||
StringRef("strncasecmp"));
|
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;
|
Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL;
|
||||||
bool isConstSized = sizedValue && isa<ConstantInt>(sizedValue);
|
bool isConstSized = sizedValue && isa<ConstantInt>(sizedValue);
|
||||||
bool isCaseInsensitive = !callInst->getCalledFunction()->getName().compare(
|
|
||||||
StringRef("strcasecmp")) ||
|
|
||||||
!callInst->getCalledFunction()->getName().compare(
|
|
||||||
StringRef("strncasecmp"));
|
|
||||||
|
|
||||||
if (!(HasStr1 || HasStr2)) {
|
if (!(HasStr1 || HasStr2)) {
|
||||||
|
|
||||||
@ -382,7 +394,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
if (val && !val->empty()) {
|
if (val && !val->empty()) {
|
||||||
|
|
||||||
Str2 = StringRef(*val);
|
Str2 = StringRef(*val);
|
||||||
HasStr2 = true;
|
// HasStr2 = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,15 +439,6 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
else
|
else
|
||||||
unrollLen = constStrLen;
|
unrollLen = constStrLen;
|
||||||
|
|
||||||
/*
|
|
||||||
if (!be_quiet)
|
|
||||||
errs() << callInst->getCalledFunction()->getName() << ": unroll len "
|
|
||||||
<< unrollLen
|
|
||||||
<< ((isSizedcmp && !isConstSized) ? ", variable n" : "") << ":
|
|
||||||
"
|
|
||||||
<< ConstStr << "\n";
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* split before the call instruction */
|
/* split before the call instruction */
|
||||||
BasicBlock *bb = callInst->getParent();
|
BasicBlock *bb = callInst->getParent();
|
||||||
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst));
|
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef AFL_NGRAM_CONFIG_H
|
#ifndef AFL_NGRAM_CONFIG_H
|
||||||
#define AFL_NGRAM_CONFIG_H
|
#define AFL_NGRAM_CONFIG_H
|
||||||
|
|
||||||
#include "../config.h"
|
#include "types.h"
|
||||||
|
|
||||||
#if (MAP_SIZE_POW2 <= 16)
|
#if (MAP_SIZE_POW2 <= 16)
|
||||||
typedef u16 PREV_LOC_T;
|
typedef u16 PREV_LOC_T;
|
||||||
|
@ -53,7 +53,7 @@ class SplitComparesTransform : public ModulePass {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
SplitComparesTransform() : ModulePass(ID) {
|
SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
|
||||||
|
|
||||||
initInstrumentList();
|
initInstrumentList();
|
||||||
|
|
||||||
@ -407,6 +407,7 @@ bool SplitComparesTransform::simplifyIntSignedness(Module &M) {
|
|||||||
auto op1 = IcmpInst->getOperand(1);
|
auto op1 = IcmpInst->getOperand(1);
|
||||||
|
|
||||||
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
|
||||||
|
if (!intTyOp0) { continue; }
|
||||||
unsigned bitw = intTyOp0->getBitWidth();
|
unsigned bitw = intTyOp0->getBitWidth();
|
||||||
IntegerType *IntType = IntegerType::get(C, bitw);
|
IntegerType *IntType = IntegerType::get(C, bitw);
|
||||||
|
|
||||||
@ -555,6 +556,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||||
|
|
||||||
if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ ||
|
if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ ||
|
||||||
|
selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ ||
|
||||||
selectcmpInst->getPredicate() == CmpInst::FCMP_ONE ||
|
selectcmpInst->getPredicate() == CmpInst::FCMP_ONE ||
|
||||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UNE ||
|
selectcmpInst->getPredicate() == CmpInst::FCMP_UNE ||
|
||||||
selectcmpInst->getPredicate() == CmpInst::FCMP_UGT ||
|
selectcmpInst->getPredicate() == CmpInst::FCMP_UGT ||
|
||||||
@ -605,10 +607,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
: sizeInBits == 64 ? 53
|
: sizeInBits == 64 ? 53
|
||||||
: sizeInBits == 128 ? 113
|
: sizeInBits == 128 ? 113
|
||||||
: sizeInBits == 16 ? 11
|
: sizeInBits == 16 ? 11
|
||||||
/* sizeInBits == 80 */
|
: sizeInBits == 80 ? 65
|
||||||
: 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 =
|
const unsigned long long mask_fraction =
|
||||||
(1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1);
|
(1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1);
|
||||||
const unsigned long long mask_exponent =
|
const unsigned long long mask_exponent =
|
||||||
@ -735,6 +738,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
BasicBlock * signequal2_bb = signequal_bb;
|
BasicBlock * signequal2_bb = signequal_bb;
|
||||||
switch (FcmpInst->getPredicate()) {
|
switch (FcmpInst->getPredicate()) {
|
||||||
|
|
||||||
|
case CmpInst::FCMP_UEQ:
|
||||||
case CmpInst::FCMP_OEQ:
|
case CmpInst::FCMP_OEQ:
|
||||||
icmp_exponent_result =
|
icmp_exponent_result =
|
||||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
|
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
|
||||||
@ -816,6 +820,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
|
|
||||||
switch (FcmpInst->getPredicate()) {
|
switch (FcmpInst->getPredicate()) {
|
||||||
|
|
||||||
|
case CmpInst::FCMP_UEQ:
|
||||||
case CmpInst::FCMP_OEQ:
|
case CmpInst::FCMP_OEQ:
|
||||||
/* if the exponents are satifying the compare do a fraction cmp in
|
/* if the exponents are satifying the compare do a fraction cmp in
|
||||||
* middle_bb */
|
* middle_bb */
|
||||||
@ -900,11 +905,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
|
|
||||||
/* compare the fractions of the operands */
|
/* compare the fractions of the operands */
|
||||||
Instruction *icmp_fraction_result;
|
Instruction *icmp_fraction_result;
|
||||||
Instruction *icmp_fraction_result2;
|
|
||||||
BasicBlock * middle2_bb = middle_bb;
|
BasicBlock * middle2_bb = middle_bb;
|
||||||
PHINode * PN2 = nullptr;
|
PHINode * PN2 = nullptr;
|
||||||
switch (FcmpInst->getPredicate()) {
|
switch (FcmpInst->getPredicate()) {
|
||||||
|
|
||||||
|
case CmpInst::FCMP_UEQ:
|
||||||
case CmpInst::FCMP_OEQ:
|
case CmpInst::FCMP_OEQ:
|
||||||
icmp_fraction_result =
|
icmp_fraction_result =
|
||||||
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
|
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_OLT:
|
||||||
case CmpInst::FCMP_ULT: {
|
case CmpInst::FCMP_ULT: {
|
||||||
|
|
||||||
|
Instruction *icmp_fraction_result2;
|
||||||
|
|
||||||
middle2_bb = middle_bb->splitBasicBlock(
|
middle2_bb = middle_bb->splitBasicBlock(
|
||||||
BasicBlock::iterator(middle_bb->getTerminator()));
|
BasicBlock::iterator(middle_bb->getTerminator()));
|
||||||
|
|
||||||
@ -980,6 +987,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
|||||||
|
|
||||||
switch (FcmpInst->getPredicate()) {
|
switch (FcmpInst->getPredicate()) {
|
||||||
|
|
||||||
|
case CmpInst::FCMP_UEQ:
|
||||||
case CmpInst::FCMP_OEQ:
|
case CmpInst::FCMP_OEQ:
|
||||||
/* unequal signs cannot be equal values */
|
/* unequal signs cannot be equal values */
|
||||||
/* goto false branch */
|
/* goto false branch */
|
||||||
@ -1294,12 +1302,9 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
|||||||
|
|
||||||
case 64:
|
case 64:
|
||||||
count += splitIntCompares(M, bitw);
|
count += splitIntCompares(M, bitw);
|
||||||
/*
|
if (debug)
|
||||||
if (!be_quiet)
|
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
|
||||||
count
|
|
||||||
<< " split\n";
|
<< " split\n";
|
||||||
*/
|
|
||||||
bitw >>= 1;
|
bitw >>= 1;
|
||||||
#if LLVM_VERSION_MAJOR > 3 || \
|
#if LLVM_VERSION_MAJOR > 3 || \
|
||||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
||||||
@ -1307,12 +1312,9 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
|||||||
#endif
|
#endif
|
||||||
case 32:
|
case 32:
|
||||||
count += splitIntCompares(M, bitw);
|
count += splitIntCompares(M, bitw);
|
||||||
/*
|
if (debug)
|
||||||
if (!be_quiet)
|
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
|
||||||
count
|
|
||||||
<< " split\n";
|
<< " split\n";
|
||||||
*/
|
|
||||||
bitw >>= 1;
|
bitw >>= 1;
|
||||||
#if LLVM_VERSION_MAJOR > 3 || \
|
#if LLVM_VERSION_MAJOR > 3 || \
|
||||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
||||||
@ -1320,13 +1322,10 @@ bool SplitComparesTransform::runOnModule(Module &M) {
|
|||||||
#endif
|
#endif
|
||||||
case 16:
|
case 16:
|
||||||
count += splitIntCompares(M, bitw);
|
count += splitIntCompares(M, bitw);
|
||||||
/*
|
if (debug)
|
||||||
if (!be_quiet)
|
errs() << "Split-integer-compare-pass " << bitw << "bit: " << count
|
||||||
errs() << "Split-integer-compare-pass " << bitw << "bit: " <<
|
|
||||||
count
|
|
||||||
<< " split\n";
|
<< " split\n";
|
||||||
*/
|
// bitw >>= 1;
|
||||||
bitw >>= 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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
|
The actual implementation on current QEMU (shipped as qemuafl) is from
|
||||||
Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining.
|
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
|
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,
|
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
|
fairly meaningless if the optimization levels or instrumentation scopes don't
|
||||||
match.
|
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
|
If you need to fix up checksums or do other cleanup on mutated test cases, see
|
||||||
utils/custom_mutators/ for a viable solution.
|
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.
|
Beyond that, this is an early-stage mechanism, so fields reports are welcome.
|
||||||
You can send them to <afl-users@googlegroups.com>.
|
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
|
Statically rewriting binaries just once, instead of attempting to translate
|
||||||
them at run time, can be a faster alternative. That said, static rewriting is
|
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
|
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.
|
program control flow without actually executing each and every code path.
|
||||||
|
|
||||||
The best implementation is this one:
|
Checkout the "Fuzzing binary-only targets" section in our main README.md and
|
||||||
|
the docs/binaryonly_fuzzing.md document for more information and hints.
|
||||||
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.
|
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user