mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
4086 Commits
Author | SHA1 | Date | |
---|---|---|---|
02294d368a | |||
d20d031141 | |||
67293b298d | |||
95f47ac3a4 | |||
3844e79492 | |||
da2d4d8258 | |||
8b7a7b29c6 | |||
d0225c2c4d | |||
ade1d2819e | |||
4e402ba9fc | |||
48cef3c747 | |||
3b5fa3632b | |||
86a8ef168d | |||
b41ea92a67 | |||
2bd7206ec5 | |||
70bf4b4ab0 | |||
b6643a8ad1 | |||
495cbd42b7 | |||
6e75832082 | |||
c30999562e | |||
3c68208dd3 | |||
b03424073e | |||
11be1fa86e | |||
400ab10cfd | |||
5dad048674 | |||
98989f1088 | |||
2019b42ced | |||
523aaaebef | |||
846a46e060 | |||
89d4565092 | |||
624c1dce46 | |||
72a4bc7039 | |||
950648c513 | |||
e41d1183cc | |||
c8e96e5253 | |||
4f93220c4b | |||
45b5e3622e | |||
43e16cf13d | |||
d0390f3b76 | |||
9d3a2b693a | |||
f2a83c4a50 | |||
b815c32f0e | |||
71f3d82d43 | |||
cd40fa1745 | |||
61a918f820 | |||
ab0f13ed06 | |||
4a0e0270ad | |||
fd8dc14552 | |||
f0d300b32a | |||
eb3aa2a227 | |||
6069cac313 | |||
92a3081337 | |||
5e72568a45 | |||
ae9087b390 | |||
36c7c49738 | |||
1fabfd5a32 | |||
be880f2476 | |||
50bb931ea6 | |||
0c06371cda | |||
86bf55ff8b | |||
ef33193d77 | |||
c19d1f0c75 | |||
019b26de58 | |||
43ca2d3113 | |||
9c517199b2 | |||
bfe7e3fd55 | |||
46e35e9401 | |||
28878c69e0 | |||
9d1be3162a | |||
7181112233 | |||
2e6e1e566b | |||
19690b606d | |||
5ab14f22a5 | |||
201d82ae0d | |||
43b1a0d46b | |||
a02d84a11c | |||
f2efd94035 | |||
96b743094d | |||
3c846859ee | |||
845c584b9c | |||
f7179e44f6 | |||
c23183f1dc | |||
99819cf5d1 | |||
53facd8882 | |||
fee7470083 | |||
afc4da47f7 | |||
d35a90101f | |||
a7141b6a6e | |||
2b4e93faba | |||
c4ad4681cf | |||
05c13588d7 | |||
050f331c54 | |||
d5fc03b718 | |||
70e9757044 | |||
6c88b6b362 | |||
8d894eec90 | |||
7a3dfbce71 | |||
7f6d256014 | |||
4291c3db5d | |||
8f9d1fd7b0 | |||
b7d12c8532 | |||
b418c31479 | |||
6514e33ab6 | |||
920e9402a4 | |||
bc99b5ba03 | |||
c4f418c3b2 | |||
67989e9f2a | |||
7a383342de | |||
01658fb2e8 | |||
cabde32140 | |||
6088a0d4c2 | |||
a26ed3b758 | |||
565f61a6ab | |||
3ff4ca348c | |||
e20f0bf0ea | |||
c9a96b268b | |||
1004fb9a41 | |||
e190ba1a2f | |||
221616a1b7 | |||
049ace8a40 | |||
89eb285a23 | |||
0709d00b10 | |||
84a99f49b8 | |||
7ca51fab19 | |||
1edc3ece61 | |||
eda1ee0807 | |||
5ee2dd6bbd | |||
eac254ae57 | |||
fa349b4f4c | |||
a50d95b831 | |||
3439d641c0 | |||
1006abffad | |||
1f3d5c271a | |||
96533f627e | |||
2c5844f665 | |||
22c696ff1c | |||
c169cb3911 | |||
00a53a870d | |||
1725e6be31 | |||
0029c1a83e | |||
c892642057 | |||
236a67621b | |||
2d662ace87 | |||
447d232caf | |||
90e7543038 | |||
3b860c1dd6 | |||
ab394836a9 | |||
d319b4a381 | |||
e1384b5086 | |||
55224e5150 | |||
836aeef595 | |||
c2b58cff6f | |||
6e2a0ef233 | |||
958436be4b | |||
7dc4847869 | |||
2dac4e785f | |||
ee5078f43c | |||
2b3642aa39 | |||
d68bd656fe | |||
8bd5d7676e | |||
70c1de5d64 | |||
2fef89950f | |||
a908a98225 | |||
82554677a8 | |||
dfe6f7f8c9 | |||
5fcd634f05 | |||
28f1e94ab9 | |||
e1d37a802b | |||
0f9dceff3d | |||
8868648f76 | |||
72a70423c2 | |||
84534ae2e8 | |||
687dd9cb67 | |||
ede03a96ed | |||
33dd2ce021 | |||
bc0ff559f5 | |||
090128b3f8 | |||
d7e121e2c9 | |||
749b03d812 | |||
fc73a18e9a | |||
7e67a735e6 | |||
14e1b0ffba | |||
e98cd00822 | |||
2102264acf | |||
e73c7c59c1 | |||
99525dee38 | |||
848ea17154 | |||
1cdf0a898c | |||
00913bce81 | |||
5be7d9c1cc | |||
44347beff0 | |||
166c8f93b5 | |||
9393452d1c | |||
66fa76a061 | |||
d2e7c4ec05 | |||
10fb46301c | |||
c397becd81 | |||
62508c3b44 | |||
94312796f9 | |||
adeeed9e43 | |||
513bd70384 | |||
cdd30c766b | |||
5e2a5f1110 | |||
a7797f0cb9 | |||
d17abce59b | |||
b715050de9 | |||
da5a32792d | |||
f36341b3b4 | |||
dda4757b35 | |||
c6f1c56c15 | |||
413807db01 | |||
f59ef29c26 | |||
65b90001f6 | |||
6840e8fd2a | |||
7c2436c711 | |||
c2df65a0af | |||
175a275a3d | |||
bd64315395 | |||
65e3770bad | |||
f5420e737a | |||
4e567d3f5d | |||
1227776251 | |||
862cb3217f | |||
8e11546536 | |||
73641be796 | |||
ff9f3fbe96 | |||
1dcc3549b6 | |||
23f7bee81c | |||
ac795ae1e1 | |||
aa6a50c2b4 | |||
62f067ec71 | |||
01ad7610be | |||
d4fb7f8b40 | |||
61c8304f24 | |||
27c0480866 | |||
b289e7ad07 | |||
70403f7e1b | |||
1ab125de63 | |||
96574854b3 | |||
281cd47c15 | |||
01ad0f3c6a | |||
db342c9c81 | |||
f1d8a01047 | |||
3753f56c25 | |||
d32b1d6b0c | |||
e5bdba4b9f | |||
c725cb71de | |||
8ff5063545 | |||
e549102563 | |||
b7d90a9e31 | |||
adeb0d18b1 | |||
16e3e2a7f7 | |||
0484d9b024 | |||
d60bbff0d9 | |||
966eba50a6 | |||
ffd8fae22a | |||
cb0fe044dd | |||
4f3b5f8adc | |||
3bb12b456f | |||
a10a627622 | |||
2777784f4f | |||
4bd0d4cbaf | |||
2d92bb483e | |||
071edb1a2d | |||
7f36290703 | |||
6cc59a38be | |||
87eb44abe4 | |||
a0c3011673 | |||
69f3095045 | |||
d678d59372 | |||
b2feada293 | |||
bff02dae0d | |||
851231c846 | |||
f21a5c42c1 | |||
d471fc9509 | |||
9f22a151f3 | |||
0c2478cae6 | |||
b865fc6080 | |||
d44b650cd4 | |||
aa12e46013 | |||
2c18fbbb2e | |||
4131965d48 | |||
5fab0fa51f | |||
9c9232b4e8 | |||
0d6e571237 | |||
40ba8814b3 | |||
a0a917ad87 | |||
8628839c55 | |||
5001779984 | |||
93d91dd7a1 | |||
791c5c171d | |||
a723156740 | |||
0868ea8348 | |||
5a6ad71f3f | |||
47f2650a32 | |||
74a6044b3f | |||
e82ce95251 | |||
e226d1bbb3 | |||
54c1087340 | |||
eb1e8619eb | |||
c96fca6833 | |||
d3f69ab4c6 | |||
517db1b8dc | |||
7f062524c9 | |||
99b4c3f362 | |||
4a0d4c50fc | |||
976cb3e36c | |||
81442ba3f9 | |||
9b3d8c327d | |||
7b907e45ad | |||
e8d580f54d | |||
2dd5a02061 | |||
9844e1a856 | |||
44be521ab8 | |||
c9819e3b94 | |||
16d6f35aa6 | |||
c9854ec8cb | |||
c429021de1 | |||
41ad23041b | |||
3e5ac0af52 | |||
f848562732 | |||
3342aa751d | |||
a2f40aa285 | |||
f34a860d5f | |||
af9aeb89d4 | |||
be5274d4a9 | |||
b6dc529bc3 | |||
0aa93afeb8 | |||
79d75d8e42 | |||
96c526cb78 | |||
02f3319256 | |||
8f538e77ed | |||
1e76079e93 | |||
0e736276e6 | |||
08ef8d6b78 | |||
3977d50b55 | |||
3bcfbf5038 | |||
f0c7967fbf | |||
8bdb40b763 | |||
f0bc2e0e8b | |||
108e588e88 | |||
333509bb0a | |||
c269c3977c | |||
c3a8052a16 | |||
d0a61279b8 | |||
7259075b71 | |||
14fd477147 | |||
05e2f577f6 | |||
a29b360d55 | |||
75d6a8b701 | |||
ad7a7fcf07 | |||
82c05630ba | |||
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 | |||
84f0b4f187 | |||
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 | |||
8e712d1a74 | |||
149ec41e90 | |||
e0ab846f7f | |||
df7c72fd66 | |||
76117b0471 | |||
ce9e127529 | |||
c5c852dada | |||
7382cf5f00 | |||
109560e73a | |||
befb1a2f39 | |||
fd30a4184a | |||
e4a113b953 | |||
7f50aa26db | |||
54f59c7403 | |||
dbbbeea36e | |||
1825e5f313 | |||
609f3d0265 | |||
12d62d5393 | |||
d5ded820e5 | |||
cc781e44f3 | |||
2bf68a0bf4 | |||
8a1acac559 | |||
1a3c9bc36d | |||
161c80014e | |||
af403e5872 | |||
a686c1361c | |||
b8a590b84d | |||
2c24cdbfc3 | |||
e5c50037d5 | |||
a8e568f248 | |||
39a4fac941 | |||
3997d06cbd | |||
2641082a76 | |||
cebbedd238 | |||
d1eb4eeb7f | |||
a7125c68eb | |||
1dbb1c7193 | |||
9534bb87b1 | |||
4e96447b43 | |||
ad29eef271 | |||
c70b7ffd80 | |||
6fb74342b8 | |||
2b543a64af | |||
5bb51688e4 | |||
6e61b2345c | |||
cf0c49dec5 | |||
064e63962f | |||
6d2ac3e314 | |||
8999023432 | |||
da6cddab90 | |||
46156957bd | |||
2f4166d5d6 | |||
e707a8d738 | |||
eda068751e | |||
5d6b1129f0 | |||
06ec5ab3d7 | |||
e6de85861c | |||
4c2e375e22 | |||
8f79116a15 | |||
f8c33f29e8 | |||
9e8e25729a | |||
9a7d045897 | |||
d59d1fcd9f | |||
1aebbd7490 | |||
330f33a435 | |||
3d233b34b8 | |||
eb85ded6ee | |||
c18ca63519 | |||
1dbefc14ea | |||
1f34b9f8e1 | |||
a19b3022d9 | |||
aca5b55b6d | |||
e9a342f3d9 | |||
b31d5a7cef | |||
f0e81b2301 | |||
295ddaf96b | |||
a2e2fae840 | |||
0f803c63df | |||
1890d7b9cf | |||
16a6bbb3c9 | |||
0942158ad1 | |||
c05e4efbe9 | |||
8584f9d2b5 | |||
f7d8643dc4 | |||
e769102491 | |||
1b75cc9f74 | |||
403b8a1086 | |||
e865f274f1 | |||
856968c13b | |||
63c317218b | |||
aff4ccb0b2 | |||
e83426a79b | |||
fdac887660 | |||
b792c59080 | |||
d1259d0914 | |||
4d9eb9bda1 | |||
cd0a25be5e | |||
b260204b72 | |||
211a6eb411 | |||
108a89b559 | |||
68e18dbb7a | |||
631b6d0187 | |||
f80f62f14b | |||
57f8aec381 | |||
23f37ff505 | |||
54fdec0e51 | |||
add108ec23 | |||
d042a63ab4 | |||
c06b5a1564 | |||
99c783821f | |||
9d22c8a02c | |||
1cc637a0a0 | |||
7000f2a2cf | |||
ea689076b3 | |||
3ac953ec33 | |||
76c5b8a3b4 | |||
40e10895a2 | |||
e750a5c856 | |||
30cd8a8397 | |||
bd313d4039 | |||
81493e4fe1 | |||
389ee822e8 | |||
fb38de8d73 | |||
155c2767a0 | |||
622f942555 | |||
7db5d87a32 | |||
79ed86da3f | |||
119d7d0025 | |||
54a312a5fe | |||
4a4c14c9a9 | |||
35fd6847fe | |||
ffe41e6fce | |||
c05c5b787b | |||
bb218b330f | |||
20a8a93fd1 | |||
14e76cf3c9 | |||
5357ae5f91 | |||
a3928e5a62 | |||
1dfd7df7c0 | |||
8e1047f5ef | |||
1661303248 | |||
4c59c5234a | |||
82d1c3e18d | |||
585ba4c1dd | |||
a728e8f9a5 | |||
3b799c09cd | |||
50c98445fe | |||
665802673d | |||
f8bbbf31ec | |||
61fe059ba2 | |||
6abe4d124e | |||
a8de605637 | |||
c43a12919d | |||
3cfc0174f7 | |||
7b4d1c4089 | |||
245f511a1d | |||
8bccf56553 | |||
7ed0bfb6f5 | |||
d795ec0451 | |||
350c3b323a | |||
d026a9a9c5 | |||
445d8f9917 | |||
eab60a084c | |||
050354a9de | |||
26d78ce2ec | |||
80401940e3 | |||
0863d940fe | |||
7d944e9512 | |||
fd20432deb | |||
a260d34b49 | |||
54ed02ef47 | |||
fdc364046e | |||
e24f8ba4b0 | |||
52512aa0af | |||
cbfd1c6535 | |||
e0fe546459 | |||
416e01d3c6 | |||
0fd98ae8b0 | |||
a0c0cf9712 | |||
ded80870a9 | |||
5a84db7c67 | |||
27c3423fb6 | |||
ed2f82eaf4 | |||
cf30f52f25 | |||
e32b7eeb83 | |||
5ecc4ae0ab | |||
f810639ab1 | |||
dfb847a51b | |||
efd27bd8ce | |||
e0bdfd87b6 | |||
b33306ca2c | |||
a2739ef5ff | |||
bdadba60f7 | |||
158efe49ac | |||
2decf1d088 | |||
3e17a90faa | |||
46a828212e | |||
d4b04f0790 | |||
9e3b818c35 | |||
9347ad49b8 | |||
abac876b3a | |||
7c8b0af84a | |||
b5686eb63e | |||
17c0d928e8 | |||
1f46171b39 | |||
587f66f1b3 | |||
93c9093817 | |||
fe705bb956 | |||
0b9b4adbd3 | |||
a09a6459ed | |||
55dd04132f | |||
d4bf0c7db7 | |||
90e04d4909 | |||
0f14057812 | |||
0d0e220b4b | |||
8cdf04ec90 | |||
987ddb72b1 | |||
29a9d3aa49 | |||
424438edfc | |||
868cb61ea6 | |||
44c65fa0a0 | |||
029d44a6ec | |||
ca938e7c4e | |||
18ad8a097c | |||
aac0ab8c67 | |||
e5f30c6908 | |||
e5c2779d56 | |||
eefc3608e7 | |||
4e99e3b36c | |||
4a5df3dcfe | |||
2e8ec1e339 | |||
aa0d378520 | |||
0e748ccda7 | |||
c866aef37f | |||
8d75c08938 | |||
982260c134 | |||
fa191017b5 | |||
73c0e1357f | |||
d0cdbc48ae | |||
ac1c3b8701 | |||
d8a058bf59 | |||
fcea01a8ea | |||
d5c3b4bafd | |||
b82e9ad3db | |||
fffe53136c | |||
bded51e4ea | |||
190a9cf1e4 | |||
1818d1c6a7 | |||
ee66cd7b27 | |||
f41aafa4f7 | |||
354bda2846 | |||
0f8529a3db | |||
ea0851c654 | |||
d1e18f9edf | |||
0139b8cdcb | |||
24e0c9cf65 | |||
7ca5524e55 | |||
638bf19b65 | |||
735e8c3956 | |||
23872d6f2c | |||
56ac3fcdc5 | |||
5ee63a6e62 | |||
c20ba2c2c5 | |||
d9b63766df | |||
5427f7ca98 | |||
15099f7f5a | |||
aef0cd5877 | |||
d6da5605c8 | |||
b7e0490bcd | |||
c03fbcedaa | |||
dab017ddda | |||
55e1726b23 | |||
59815cd447 | |||
6a397d6111 | |||
01ec0cce47 | |||
5540a055c5 | |||
445aba9221 | |||
5dc3bc175b | |||
c075003bd2 | |||
1ab83d7d89 | |||
cbf8212fe0 | |||
e5de66e463 | |||
125f8b6ba7 | |||
4cb4772e2a | |||
43d8296504 | |||
0220a8ff66 | |||
fd4a2dfec2 | |||
deab5a1532 | |||
c12b98e0a4 | |||
794e8d2d67 | |||
1fd2ffaf14 | |||
3e16cf5fbf | |||
17abe7d36e | |||
3d7bdc9f0b | |||
f519fff7bc | |||
231420775f | |||
2d5fadc1e6 | |||
4f207b4eba | |||
693252c737 | |||
74dc227c44 | |||
a4b60ca5b6 | |||
fd4efd04a1 | |||
9ac9aa2511 | |||
916b6fd317 | |||
2bf3a70e2b | |||
9b112fde1a | |||
bab60b68d9 | |||
1a12db1b59 | |||
1e0bc2e5c3 | |||
b0de6fed11 | |||
ca6106a1dc | |||
6006cce0cf | |||
ff8c6d2415 | |||
26dcddab0c | |||
2239743361 | |||
383cd487a2 | |||
fe08482c1b | |||
e87eca7fe8 | |||
e69b25e34b | |||
e85fde201e | |||
e301822c68 | |||
a55e0d1189 | |||
fc75d2b181 | |||
6b3b1775b6 | |||
3334eeb4eb | |||
e38ca0e750 | |||
a75e7594f7 | |||
888d63748a | |||
818c05cf29 | |||
60ef1f7305 | |||
b3b5e25091 | |||
f4a0407270 | |||
daa2285083 | |||
639372b644 | |||
52c135e1a2 | |||
093754f6bf | |||
207cbd5cf7 | |||
f34fe1f81e | |||
5f52f72761 | |||
6d99695108 | |||
a18523f018 | |||
7ff9800804 | |||
44c0dc6d96 | |||
1225f3aa70 | |||
9eed8fe588 | |||
4561a9590f | |||
5241d1221b | |||
a95427a873 | |||
c5c5570d97 | |||
3abace4f54 | |||
7cdbe3173e | |||
7f94fe3587 | |||
060dbe1239 | |||
a9ba907676 | |||
fe39e0184f | |||
688e2c87df | |||
38e6de1eff | |||
862b6d0382 | |||
543765bc0d | |||
380051868a | |||
fdb0452245 | |||
454a860020 | |||
a4cac3fce5 | |||
f8c0182e16 | |||
d3282ef1fe | |||
9b6564f0a3 | |||
eb9f323d7c | |||
fe98e2d760 | |||
ab744abc4b | |||
2802245da7 | |||
c091340a85 | |||
3890225c35 | |||
9544b3dbf2 | |||
43cb626ad3 | |||
13f2ac83a9 | |||
374e068f97 | |||
10f775be07 | |||
3565641c41 | |||
679b2d63a8 | |||
6404abd7d6 | |||
7bcbfd48e5 | |||
06ac2850c5 | |||
6114a48b89 | |||
e065ba9497 | |||
8ec41b2585 | |||
bd007c151d | |||
163e5ffd10 | |||
ded4d093ff | |||
2508922288 | |||
39c020ec74 | |||
81b1d85f61 | |||
2f90f2faba | |||
e30b2c6af6 | |||
4b3ad5f037 | |||
996986bed5 | |||
ee206da389 | |||
fac108476c | |||
4f7a8a4c70 | |||
976ee9022c | |||
0625eb0a05 | |||
77b824d101 | |||
b7b38205d8 | |||
6c715f1a69 | |||
fc19aa96f7 | |||
50f61b64b1 | |||
809a7cffe2 | |||
6399f84ba2 | |||
8459bcdf85 | |||
6adaacbb3a | |||
6c846bcf2c | |||
e45ae8e5da | |||
cea2fadbf4 | |||
4c48d3a3ad | |||
c39a552cc0 | |||
020b8a4964 | |||
08f6e1d66a | |||
28e457e8d8 | |||
c7255f2e26 | |||
6340674a23 | |||
4538f689ed | |||
415b759ed1 | |||
e4a86b40a5 | |||
b8d3a97a4f | |||
75c38d6243 | |||
6f75100602 | |||
07cee6b750 | |||
651ad18e21 | |||
664daa2f3c | |||
ed6243df5a | |||
bd57784664 | |||
7f621509ee | |||
4261e17b3e | |||
8ca4414d70 | |||
6090bb1bca | |||
a552631d3b | |||
c552229c4d | |||
2dffed1cff | |||
e93f78eca5 | |||
9bbbec3fa8 | |||
338638b124 | |||
17e1a72b3b | |||
3e6471b949 | |||
e4de4e3500 | |||
bea76b346c | |||
53e63e9ded | |||
b1b5e21600 | |||
d765740707 | |||
192cadee34 | |||
d7d8afa512 | |||
01fcee1190 | |||
0805437222 | |||
4398b9b517 | |||
909262f6c5 | |||
155ef8875a | |||
58cf030546 | |||
18ea9a8447 | |||
ebd1e6bc4b | |||
45d866d548 | |||
8087cf7988 | |||
9e8b3f13e1 | |||
ce4700ca6e | |||
8253f90134 | |||
86421f3469 | |||
811ef13b20 | |||
7fb72f1038 | |||
d2c9e4baa7 | |||
81767287c3 | |||
6c980e2a02 | |||
e7db4d4fe0 | |||
567042d146 | |||
4697e4a5a5 | |||
92b1f9cf36 | |||
bbf00204ea | |||
a42b74b624 | |||
7ee255cbcf | |||
961ddfd7f8 | |||
4566bcf122 | |||
ca0105ddf6 | |||
41bb359428 | |||
146ede0f29 | |||
c0fd7ba6d1 | |||
b0b2a15891 | |||
ff3c9cbd73 | |||
6e839f0f6a | |||
a3cd523250 | |||
b44620f0b0 | |||
9a6a32775f | |||
3e8beaafc8 | |||
33e58c1d4e | |||
4be0ea596b | |||
96ef7083c8 | |||
78eaa6b203 | |||
1efc6e59b7 | |||
19eddbb0c7 | |||
6a34c5aa3e | |||
c7f0d30668 | |||
a7c3f252d5 | |||
b9b6f06429 | |||
a1442bd1ac | |||
4d9d52e3d9 | |||
6184832ea9 | |||
e2b54bfa05 | |||
425908a00c | |||
1301552101 | |||
c4f71ab201 | |||
42ef1968a5 | |||
5ec91fce23 | |||
47878f6974 | |||
d5c77a9e96 | |||
4d2694c114 | |||
017c8a6940 | |||
b0a783e86f | |||
714e4d2b46 | |||
85a4c5e724 | |||
182b8b3e14 | |||
4ce5ed370a | |||
f7bac482e9 | |||
bd074e9150 | |||
d52ea44c27 | |||
9c1b6cfb99 | |||
631d3f274a | |||
3cdaf4dcf2 | |||
572944d726 | |||
779d8f6b7e | |||
322847755a | |||
f9f28b9c7c | |||
c3bc0145e7 | |||
17d403b8f8 | |||
9faf7b6fc8 | |||
5c759953f4 | |||
1c64048d0f | |||
b504b9313a | |||
1a94cfe2af | |||
7470b475a9 | |||
0a6084f361 | |||
f92607cff1 | |||
9532499ef5 | |||
1d56de6c1d | |||
266b51a842 | |||
cc1fe2f2d2 | |||
43214d6b46 | |||
2f28ecd3a5 | |||
73a629d6f2 | |||
0a251f93e0 | |||
1cf4738487 | |||
af14acf2c1 | |||
a7537b5511 | |||
15e799f7ae | |||
5f0a9c90c8 | |||
9ff9ff2ad2 | |||
d86b13384f | |||
17a4e9fadf | |||
ce513c4f3e | |||
ce92adcb9b | |||
e94cc1fae0 | |||
32fe047894 | |||
d1bc0207cc | |||
69f8c62955 | |||
83df65a66b | |||
c3a6e7e870 | |||
d0ab83a202 | |||
b5d1a021ef | |||
e9fb5f4cbc | |||
212bb990b7 | |||
8e984c2aa0 | |||
7f435ec5f1 | |||
47faf3dd33 | |||
c4e52e20c9 | |||
2c5e103278 | |||
7a6867e2f8 | |||
8044ae28be | |||
b38837f4ff | |||
c25479264d | |||
e9b3da5d96 | |||
132b57cf03 | |||
ee548df05f | |||
052d74b16c | |||
83281503b3 | |||
b604f5eafc | |||
220dc4a43d | |||
457f627101 | |||
4f695b6f4c | |||
3ec1b23743 | |||
0ba09ee85a | |||
67dac15226 | |||
9cf8637fab | |||
50e76fce12 | |||
432638404f | |||
1e38c10efb | |||
701fb95d24 | |||
7b5a18428e | |||
7d7a8c7c39 | |||
a422fcaa40 | |||
fee58a4d1b | |||
3ecafde29d | |||
8428b18d2a | |||
9c953ab51f | |||
f181a8307b | |||
84b9d551fd | |||
8f8555dfdf | |||
464c27082a | |||
3aa7d8081d | |||
fb84103ffb | |||
c270646722 | |||
87da1e7af6 | |||
9b71f7e5e4 | |||
9945c1648b | |||
e5d24827de | |||
a6521e89fc | |||
5e36fb32a8 | |||
fb0181f5bc | |||
6fa2c213ef | |||
9ec223c844 | |||
558a82891a | |||
4fc16b542e | |||
ff40359a60 | |||
e99d7e9730 | |||
b60663c031 | |||
32db31b555 | |||
a1129b67c2 | |||
8a1cf3f0f9 | |||
0bb59ba116 | |||
e4a0237cbc | |||
d8f5502d83 | |||
45d0e4765e | |||
9a1d526ed4 | |||
ebc6f52868 | |||
a19b31bf82 | |||
28251a495a | |||
f4592a8fb4 | |||
b29d91edf5 | |||
986af28df2 | |||
27abecbff5 | |||
33141cf8a3 | |||
8551d8e48e | |||
32558bc807 | |||
934cdc32f4 | |||
699ebaa8e2 | |||
44ad516edd | |||
fd9a7e719d | |||
e51f1ea5a5 | |||
22d3a5e90a | |||
673ace2a4b | |||
4a6d66d8c5 | |||
1978629d87 | |||
6b1ad311da | |||
5b06166144 | |||
a0fab35bbf | |||
420b202124 | |||
fb14e55cc9 | |||
e2434cf8c6 | |||
d94681186d | |||
58a710d192 | |||
716eb226b2 | |||
cb3631a322 | |||
bd1d148f83 | |||
7e0c9a36ef | |||
bbfff7d472 | |||
e048d95660 | |||
970d75d681 | |||
51f3a81037 | |||
8190436f8f | |||
08bcaa135f | |||
c4e5f75728 | |||
1064c7114e | |||
0281872ddf | |||
c6bf23377d | |||
2d650f8c22 | |||
19631851f6 | |||
f30ca1476c | |||
0712d44cbc | |||
15f3210d93 | |||
9864d9c189 | |||
bd36aac60a | |||
4a859aff70 | |||
8fc727e597 | |||
585ec04503 | |||
a1c93f24d4 | |||
f6c89ec3a9 | |||
3d8f054580 | |||
6d364dd2cb | |||
8ed6207b5c | |||
c8354d7516 | |||
79f873a597 | |||
8850e1a5bf | |||
194188fe56 | |||
cc74efa35e | |||
e7f2770275 | |||
af277a0b56 | |||
4163f47e09 | |||
b2aa8b03d9 | |||
e1d20706ca | |||
76888fdf59 | |||
e6e38d1703 | |||
44060590b4 | |||
38bed607d1 | |||
ed63364a77 | |||
55bd24b0c7 | |||
f18c2eb8ae | |||
898353c87a | |||
d5d8d664d0 | |||
409e4ae945 | |||
f335c48686 | |||
9d82c3cf5e | |||
491cee669f | |||
e0d1529061 | |||
1cddd51662 | |||
6041b1c486 | |||
349fed3fcd | |||
b708cf7d45 | |||
a267ff1ab5 | |||
8e0c776137 | |||
4512377fa1 | |||
9439ba1dac | |||
9c9c4a6b2b | |||
6efe51a8a7 | |||
593940c39a | |||
8ea19d4266 | |||
b7bcc50c61 | |||
e939677726 | |||
ca17ec3fe9 | |||
54d9668580 | |||
16b674c652 | |||
25ad992c62 | |||
37f1b7cddb | |||
729445b64f | |||
185f443659 | |||
c101a3f5ab | |||
cf9cb73afe | |||
071fcac430 | |||
a74ec89461 | |||
630d2a934b | |||
d5758c138b | |||
149b0021b7 | |||
68f46f6178 | |||
cd576fa59d | |||
320f26d26f | |||
c661587128 | |||
486e5365d9 | |||
8e809d8593 | |||
ea9ba53cdb | |||
1ba48a5ba0 | |||
7cb00b69f0 | |||
cbe8f0a9d0 | |||
da8b464e67 | |||
13350bf22f | |||
5ce55d87ec | |||
fc401f1acc | |||
fe39e4dfdf | |||
49b77207dd | |||
35a448ee92 | |||
3f9f00a798 | |||
ffe5619a9d | |||
3b194e1690 | |||
45b6508339 | |||
22921c493f | |||
f32811922e | |||
6cfa27d78a | |||
8e3ca8eaa9 | |||
4550613f58 | |||
015fde3703 | |||
827ecd61f6 | |||
565da10a8f | |||
d64c0e8887 | |||
0b8c44cbb1 | |||
a22f4dd1ac | |||
952e5b47eb | |||
b3f5b566b0 | |||
0b3332d579 | |||
a76e375d5c | |||
8b21c2e472 | |||
23718e5198 | |||
031aa240bc | |||
7944009a65 | |||
4eb06bb54b | |||
bd5308d839 | |||
b508532c78 | |||
fb9888a068 | |||
11f25747a9 | |||
8ebed3471f | |||
85684cd8b7 | |||
2585a33005 | |||
1bbeef48e1 | |||
7f3317110e | |||
298ff5c7d0 | |||
c3f65bff5b | |||
2323c30b5b | |||
80f4b32f0b | |||
16e362d2b9 | |||
23da490f26 | |||
ff107714f1 | |||
7e4703c328 | |||
ae41cedafe | |||
a879f72131 | |||
131df8bec9 | |||
89557d1607 | |||
7959808384 | |||
ecb0601bc1 | |||
30c0991543 | |||
9cddbc0420 | |||
2fa31dab60 | |||
4898db80cb | |||
aa3856261d | |||
3e04dbd5a1 | |||
72b46a07d6 | |||
2ba88dcd8a | |||
1ddb70e0d9 | |||
024a88a6bb | |||
af10c05ac3 | |||
a46a733dbe | |||
b015e4f07a | |||
44928a0265 | |||
d90328f6be | |||
ce9b4698fe | |||
9a33a29b4a | |||
b6e65f9882 | |||
6c163910ee | |||
9151cb9ba2 | |||
204ae75d7b | |||
f2d9b0096e | |||
67d2e6319b | |||
5e10f660e8 | |||
0da0b5cba0 | |||
67d7c364f6 | |||
67d58e2437 | |||
c2b04bdf6c | |||
6513bca07e | |||
0b0366d9b4 | |||
f465a75b65 | |||
4314e59af9 | |||
a84c958647 | |||
1ec2615a3e | |||
2077309c8d | |||
08d3169df4 | |||
3cc0445e27 | |||
ee77fe4094 | |||
133dfc8b69 | |||
a8726b8254 | |||
c5963f707c | |||
383b280531 | |||
95276f7da6 | |||
e1d4621796 | |||
e137b40eb5 | |||
4d929f80fb | |||
6b79e1f76d | |||
5a26656ea1 | |||
abb0d47985 | |||
b126a5d5a8 | |||
571031a467 | |||
2981f2025f | |||
c3a6065a21 | |||
60bb1afc72 | |||
84a320f834 | |||
88bd460100 | |||
90adc2cb85 | |||
7c8d823396 | |||
83790d65af | |||
70bd0f799d | |||
cbe029664e | |||
cade0214db | |||
2f5cdb72c8 | |||
0aed549df1 | |||
75fa1ac3b0 | |||
b5a00312e0 | |||
37697127dc | |||
8acc8b5389 | |||
8644c42482 | |||
20e63078f0 | |||
95fd080ca1 | |||
7d0af01d8b | |||
0f0230b068 | |||
869c602b99 | |||
3144f72e1c | |||
147b0a151c | |||
29102d6bf1 | |||
4fd145c52e | |||
e6d4d29af5 | |||
139665c01d | |||
509b991607 | |||
c671ecb511 | |||
1aa7c87ea8 | |||
00abb999e3 | |||
4a51cb71fb | |||
f2efea4b46 | |||
e15a013696 | |||
857046ede5 | |||
4515e06ca8 | |||
97cef46b62 | |||
4ec29928bf | |||
ba79777bc5 | |||
b67905c40f | |||
6b98157c1a | |||
4d2ccd18f6 | |||
52a0410d92 | |||
d898418037 | |||
2aaa60e4fc | |||
e9dce31496 | |||
b201279ae5 | |||
be83f06b2f | |||
9d5007b18e | |||
7527c76c74 | |||
06264df168 | |||
878b27af76 | |||
4b99ebbf22 | |||
fc5cfc6cb3 | |||
6d9b29daca | |||
3f1288e2f9 | |||
8f1b78f49e | |||
07648f75ea | |||
3a0c91b862 | |||
e5e485fcdb | |||
16f3df7cc6 | |||
6d0f086d9c | |||
c25a602a03 | |||
81974c4d5e | |||
5f3b7e6cdf | |||
910b9f3f25 | |||
4fd2cb2ce0 | |||
e234a6ae4e | |||
ee17782e61 | |||
cd6954e3c1 | |||
29e41a09d5 | |||
4103687f76 | |||
976e99b1d4 | |||
da7c548452 | |||
1ecfd78418 | |||
07fead0466 | |||
8bd8442bcc | |||
5904083231 | |||
171b1923e9 | |||
8d5eb9487d | |||
633a3feab9 | |||
c8f60a7fbf | |||
3a62bb68e0 | |||
8178f4dfdd | |||
4a3305c007 | |||
9858bc81a3 | |||
b5573b3adb | |||
15dd4ad177 | |||
d540971443 | |||
1d7c76d141 | |||
224a49341a | |||
fce010f051 | |||
bdc8e3b79e | |||
9289af040c | |||
49a769ac06 | |||
2b450aeb20 | |||
5f1c0111a6 | |||
89f0dc2d14 | |||
cffb0e9a25 | |||
2b26e3867f | |||
aad433e11e | |||
59e1a18197 | |||
8f98044d69 | |||
6c414409d4 | |||
7119bf5d86 | |||
ea1222b33f | |||
37edfe2de9 | |||
76a2d9b59b | |||
87f127722c | |||
a49b5ef072 | |||
5cad92e57e | |||
f6ef1fe65e | |||
048e429356 | |||
eb3cb4bbf8 | |||
b0866f59cc | |||
b3b016a4a3 | |||
341e17bf53 | |||
eb4561e3a6 | |||
990b234067 | |||
07a4e6370a | |||
1381e96d8c | |||
5ca303393f | |||
de2c565953 | |||
2a254fce8f | |||
758f136d3e | |||
5d3d86c680 | |||
d8d5adeb61 | |||
003456f770 | |||
25c3a29004 | |||
394d8ade15 | |||
118cc88429 | |||
61107c59cf | |||
0dc9967984 | |||
889e54eab8 | |||
a14f3c90a8 | |||
e05ed58bf8 | |||
d6824d540b | |||
2e35326040 | |||
e5dcaa818e | |||
bac2da8669 | |||
9c293b5b7b | |||
6804065a8d | |||
246444dd57 | |||
6a216b5708 | |||
f6d2da27e3 | |||
ada59feda8 | |||
af8d4d49ed | |||
dc002b4b35 | |||
acb0a2f027 | |||
43bbbbf4e0 | |||
05da66b5e9 | |||
b8cea84195 | |||
741dce3ca6 | |||
67d87dd2a9 | |||
ab142282a3 | |||
bfe5b88e78 | |||
fc26001b50 | |||
1542c7f49c | |||
615ab1a7b8 | |||
ce1af1bc9c | |||
ab0e3fdd82 | |||
40aca0b6b3 | |||
a632c00b0d | |||
db2e04361d | |||
7d19b108c4 | |||
818afe6232 | |||
e8da5f9e28 | |||
b3fee6cab2 | |||
da7a8ce60a | |||
a6386bd640 | |||
b3feda052d | |||
c1eb2bccaa | |||
5cb6dc7795 | |||
af66d8027b | |||
4ee4495120 | |||
c02721775a | |||
cbdcd32959 | |||
12bdefe00e | |||
81829d132b | |||
5fa0f8f55b | |||
7e818e877a | |||
32a40ab5c5 | |||
c2087b7c13 | |||
feffae60dd | |||
8e3f6fe2dc | |||
92b8c5bb60 | |||
646237e234 | |||
b4f71c7cc7 | |||
73334207ce | |||
e8a6b1cfb5 | |||
748238d6ab | |||
5fcd4bb082 | |||
a1aef91e39 | |||
c2c128dd67 | |||
372206e159 | |||
c036108b59 | |||
b5c77cf4f6 | |||
2b33be939a | |||
e01cad2f7d | |||
a1beb72cad | |||
a9348e0acc | |||
9a1e22afab | |||
855ee06247 | |||
f1ad9bdaea | |||
2f73215d4f | |||
155405e0d0 | |||
88e83c7322 | |||
35ddec7aeb | |||
e11922e5cc | |||
a79c002145 | |||
ea91cfdf9a | |||
031e4300a5 | |||
dd0ca7335f | |||
686d8823eb | |||
a5d554c3ef | |||
177db9cf79 | |||
2d8c3d2934 | |||
f1192b2d16 | |||
fc164e4709 | |||
1c95e2e8e0 | |||
9962de1a4c | |||
304a72c1ff | |||
83112ed5e0 | |||
fbd781fc83 | |||
62306f5ce8 | |||
1d15048f2f | |||
adcffce0a0 | |||
9a65fe904d | |||
ac998e9222 | |||
15c0ad60c5 | |||
0de25f08ba | |||
bca7ce8043 | |||
ee14785f68 | |||
c0ed118ba5 | |||
0adb664a31 | |||
4a54328901 | |||
24508194c2 | |||
95b46b4278 | |||
b16ccb4811 | |||
4119752f83 | |||
b7b5fdf42a | |||
dbd9423fc0 | |||
8f19becb62 | |||
38e5c32a55 | |||
0c50945303 | |||
8726d7b0a3 | |||
408ef5298b | |||
2ce243bc6e | |||
255594ba3a | |||
8bb0232ace | |||
e3efacaae6 | |||
a550df4301 | |||
710dda5221 | |||
c3b864d8d4 | |||
6892018142 | |||
84df805ed3 | |||
9c286da29b | |||
92b7974f44 | |||
38860323de | |||
8316425375 | |||
0cedc8014b | |||
8aae1fc5d7 | |||
4ad3144f50 | |||
4b01d594c4 | |||
5e4cd05e04 | |||
7cf01b10b7 | |||
eb7d1e22e5 | |||
0555b26161 | |||
bb0a31158a | |||
bfd2b6298e | |||
b87d97aa2b | |||
48b2028af8 | |||
92be4ea871 | |||
8a2656681f | |||
5671cae225 | |||
ef8d252843 | |||
af670ca138 | |||
aace0d1192 | |||
cee4b4593b | |||
434ccf3df4 | |||
b81df11d8a | |||
dab498c3b7 | |||
d5bb9731fe | |||
9dd0b7c6de | |||
1cae68dde3 | |||
996e1515b3 | |||
f6808158c5 | |||
7e4c5b3636 | |||
0994972c07 | |||
a0da531170 | |||
46a0f812b1 | |||
de78f867a4 | |||
707145c491 | |||
1e597a64dc | |||
4c394a9d7b | |||
3eef1560a2 | |||
fc574086ec | |||
68e66fa920 | |||
38df6eb3a9 | |||
0245f8438d | |||
d7ea8356a7 | |||
c64ea49432 | |||
38fe1c6066 | |||
74f01881e3 | |||
0f8da71588 | |||
7d3cfcfd0b | |||
536397b22f | |||
6253bea73c | |||
a5ef93c83a | |||
5b9dfa0600 | |||
5d0bcf8152 | |||
83007f77f5 | |||
c456e20750 | |||
982017a2ab | |||
3b4cd98498 | |||
0ed767fac5 | |||
25fbec6638 | |||
ae6c30a711 | |||
c7b1ed2395 | |||
5d0f020648 | |||
74e6fbab82 | |||
30824bc58e | |||
d146965025 | |||
e1e155022f | |||
d37a8f72d6 | |||
9dd3e3e38a | |||
b927b80e10 | |||
af6736c356 | |||
6e98b3ebb2 | |||
afb81b8005 | |||
2b922e9e68 | |||
57637ba0b0 | |||
d536ddc240 | |||
564399bd75 | |||
87a693d1a9 | |||
49bd24144a | |||
182b8a4582 | |||
97bddc8cfa | |||
a55e26959b | |||
63e2222af1 | |||
9637fe8a74 | |||
c084458294 | |||
498e9f4298 | |||
13033034db | |||
749c63d3b3 | |||
73c2619c33 | |||
65f9553365 | |||
3f621c8ed4 | |||
11f3b487ee | |||
4c253aedae | |||
efdad526ee | |||
4081a8f7b6 | |||
867f948bb2 | |||
767ed8c5da | |||
f0aadc3d0b | |||
d95c4483fd | |||
00a147b244 | |||
74eae83b54 | |||
324b44872c | |||
94a1d4d3ac | |||
a3392007cd | |||
4ac06a4eef | |||
0495ded87d | |||
64b80b3201 | |||
fa20eb1de7 | |||
ae15803bf1 | |||
9e375179d8 | |||
460760d7b6 | |||
682b620922 | |||
6b69cd2e57 | |||
56a86bb9e2 | |||
00ad2ffc61 | |||
a16e92800d | |||
7c9ff4bfe7 | |||
d334093606 | |||
044bd3cb41 | |||
4e192db13c | |||
8cc5442401 | |||
bd94d5fce7 | |||
b6be906082 | |||
60a5df5262 | |||
c384a17b41 | |||
6fdd6004f2 | |||
c4fe6f5277 | |||
645e331559 | |||
45bddcd808 | |||
9627458ecc | |||
f8b3d34225 | |||
5273c61cd8 | |||
0c1c947aaf | |||
6224ae1c60 | |||
72f4a9f678 | |||
060f4ea320 | |||
6177954773 | |||
7b40d7b942 | |||
1317433a51 | |||
a578d719e1 | |||
8bb10c3bf1 | |||
b920cd2f23 | |||
38dac93f63 | |||
6f66be12f6 | |||
4ee93331dc | |||
30a675ab87 | |||
845522f59b | |||
f37be09a92 | |||
ed877f5e3e | |||
d916403927 | |||
41f6aa7940 | |||
50a63777ec | |||
26fe7a9d66 | |||
07a0e2caf7 | |||
30bfd44dfd | |||
26f8708fed | |||
3beec8d4fa | |||
2e553bcd69 | |||
0e5a5f1805 | |||
d02cfc54b6 | |||
7b9ac9d414 | |||
515de0d68d | |||
1eeb6785ad | |||
20392878f1 | |||
102067d43d | |||
6c88e21459 | |||
041f19494e | |||
8e9f507bbc | |||
c380819e02 | |||
fa84e52af0 | |||
cf9238e09d | |||
190f3024da | |||
768053b6f2 | |||
bdd2a412c4 | |||
d217c7df05 | |||
9484da57ed | |||
ef2ccc8117 | |||
02887dc164 | |||
d048af11cd | |||
0559d1d171 | |||
37b681ac11 | |||
f065ddbdb2 | |||
140053502b | |||
58fad91b0b | |||
01b5aa123d | |||
8cdf767bf5 | |||
e910882e32 | |||
a1c9c497d5 | |||
a63c838b10 | |||
b7e574607c | |||
10e6b4e454 | |||
ec5b1924c4 | |||
80ddb484de | |||
cafb2e540e | |||
b4e3f22259 | |||
df52157834 | |||
a13958b32b | |||
a31b58eeea | |||
e31b816aa0 | |||
0e5027d8d8 | |||
dc79533191 | |||
128e4d5565 | |||
ad3960580d | |||
00683d06c2 | |||
a38980c80b | |||
664a180d72 | |||
d6346561db | |||
d82ada89fe | |||
9d384b4e38 | |||
6e45e55d82 | |||
ecaccd9739 | |||
95a2d49232 | |||
16c16b3e6e | |||
945e00b73f | |||
e592b4bcf0 | |||
96ef2d3821 | |||
2d126dc750 | |||
13a32e9595 | |||
73f7164048 | |||
5b1b986c89 | |||
1c53bbea52 | |||
0c5c172a30 | |||
ff1643d81f | |||
378573ab8b | |||
33ddf6ea0e | |||
a2bc3538f7 | |||
636e98d151 | |||
9f01737fa7 | |||
be4e5d2617 | |||
cc78fb721b | |||
bb7d2a7347 | |||
9d03763d94 | |||
3cf4529f3c | |||
477fb58311 | |||
59043b24cc | |||
15547eb654 | |||
16f9cc7369 | |||
efa9df24c2 | |||
a37eca9df5 | |||
e68d2345d5 | |||
fced3e00ce | |||
c53663c7ac | |||
bc2e65e482 | |||
ce2814967d | |||
781725aeaf | |||
9276dc9e6c | |||
c7de368dc2 | |||
fbd9994f6f | |||
087c368242 | |||
a56354a893 | |||
a5d4c8d532 | |||
a46fe3ad43 | |||
4ffa5b0636 | |||
62ec52dd95 | |||
ea876e59a8 | |||
66eee34709 | |||
85627516a4 | |||
b26ee09f71 | |||
fb89b042f8 | |||
646aeb2b18 | |||
2a60ceb694 | |||
80916a3613 | |||
0c3d06c41e | |||
07db922024 | |||
fa610270ab | |||
cefefba244 | |||
42017bbeda | |||
a3ee281e2b | |||
232290108e | |||
5c017d7071 | |||
62aacf88ab | |||
b3e77d3d50 | |||
766085293d | |||
4a593d0405 | |||
82b6b8c87e | |||
b6f9f4c436 | |||
b120ca27f8 | |||
5eb1f3a4c6 | |||
8ada9d06e8 | |||
cce8c4dbae | |||
3502db1ac5 | |||
df8a0e8418 | |||
b8a25063f6 | |||
6df21f3489 | |||
dcba2c3642 | |||
059c963467 | |||
ce9c6df456 | |||
0aef3b4040 | |||
4cc0589440 | |||
96722083d8 | |||
ee238eb00d | |||
45ccc7d475 | |||
a32d2ad193 | |||
f25919ad56 | |||
ae524d856d | |||
9be4f9c055 | |||
40e5b285f2 | |||
3ca787ba76 | |||
137b9ecf5e | |||
2509624add | |||
8c6fcd98be | |||
7dc825dbe9 | |||
6b3336d107 | |||
ceeb266273 | |||
9bb0733eb5 | |||
22cdad2d20 | |||
8b3befea6d | |||
5b9928f1a9 | |||
856a59901e | |||
19d0961020 | |||
3bd5e65edc | |||
b520046ab6 | |||
d22550a520 | |||
6f994ec56b | |||
09c8e40363 | |||
8e44c06a13 | |||
358f17f615 | |||
b109e31722 | |||
b77458ae81 | |||
cfeb8e83f7 | |||
0fa9ad46ae | |||
cfb11177cd | |||
0a1979fd20 | |||
0dc64b93d8 | |||
f6c9acd518 | |||
68218dd31c | |||
441b64b467 | |||
8b319969f3 | |||
41b1787565 | |||
e6fccdd9c1 | |||
0ffef8c79d | |||
3d52079a7c | |||
e47c29e728 | |||
280374f739 | |||
ce15937717 | |||
c8f2ba5b49 | |||
3dbfd18f36 | |||
4be0ae2008 | |||
67b39050df | |||
4ccd8c1400 | |||
4f997665f1 | |||
b6a15d9719 | |||
e90194093e | |||
4c90293e44 | |||
8197e9b2e4 | |||
baec99079f | |||
16a5e6bf16 | |||
39f715982d | |||
724d4ec3de | |||
e4670d3abc | |||
8aa86d063a | |||
c1d9e00044 | |||
0827a447d3 | |||
2874565b36 | |||
8ed3126f28 | |||
b408fdffcc | |||
d9cd600c1b | |||
68f18923ab | |||
9e74a7dfe1 | |||
0b5b888f82 | |||
46854b439a | |||
8ffed4b859 | |||
3b8cd9652a | |||
269050aee3 | |||
6e753f8f0f | |||
9adcc73d61 | |||
ddea300822 | |||
9900c92ebc | |||
0bd1264faf | |||
49753eb2d0 | |||
c9605f2251 | |||
6ee11c2a6f | |||
ef1d384184 | |||
a6d4f04019 | |||
87d27b8616 | |||
f22d8120ef | |||
8ecfbcdf34 | |||
263daaacaf | |||
d3254d8066 | |||
76e15a0695 | |||
1931838a11 | |||
6bd49b1d5c | |||
2d4d16755c | |||
bfcf6db17a | |||
bda4d8812e | |||
f70d4a6fd4 | |||
90ff345d73 | |||
8fa5d4c313 | |||
2162fd8e1a | |||
248a2f2f0b | |||
ef311ec70c | |||
5b70d23211 | |||
16ce555845 | |||
c961925356 | |||
23ea727915 | |||
f157bca548 | |||
35937e6263 | |||
69bd7c16eb | |||
6940e13629 | |||
380ff114e9 | |||
5e53002303 | |||
872d1c1d98 | |||
94187837c7 | |||
ede3545d8b | |||
cdac882834 | |||
1ee224652c | |||
8511638afb | |||
b10007a7b5 | |||
19ce862810 | |||
124665b392 | |||
b420ccdbf8 | |||
5e8f385705 | |||
dcc889a264 | |||
f3789801f2 | |||
0f08b13fa0 | |||
2ce6e7a7fb | |||
83d5864203 | |||
7e2c52f2b9 | |||
e88f364282 | |||
21f696f02e | |||
ef1ea07e68 | |||
0c02a8f4d3 | |||
48f7f7a17b | |||
115ee8bad5 | |||
c009896c34 | |||
6dc36f1e6e | |||
f4436f118c | |||
8440aaea5a | |||
0d0338012b | |||
5ac1b6e940 | |||
92aaaef381 | |||
2c87e68ad6 | |||
26e690c220 | |||
b63dd7a464 | |||
d2a7628748 | |||
b1e7b834ac | |||
9eb47a924a | |||
1d62bf1c37 | |||
982d46e7cb | |||
1fbface656 | |||
1374e65401 | |||
0fab4e1955 | |||
a2574169e2 | |||
4b88e059ef | |||
12a7059ae8 | |||
a897f355a9 | |||
326ab632c3 | |||
dda096da03 | |||
5daec436f9 | |||
033c743a41 | |||
459d8f9ba2 | |||
0022cc4782 | |||
995e556065 | |||
a93268acec | |||
e70c54547e | |||
7919545499 | |||
5a8db5954c | |||
ee4e1936d0 | |||
ec67780854 | |||
aaf8835cdb | |||
0a525f768b | |||
4ed43b7632 | |||
5e09e13ece | |||
eec725a345 | |||
fd63344ffc | |||
90a9f22c3d | |||
cc3ac932d9 | |||
d8947d1fa4 | |||
32ba60185e | |||
8bcfba8231 | |||
68f269437d | |||
29ee3a1ffc | |||
39e8b91806 | |||
3ab7fcf5dd | |||
3a509c6168 | |||
6dcbc4dff4 | |||
d928b148d8 | |||
3209a9d4e8 | |||
f0f83bab52 | |||
6aa6af04ac | |||
5b977453cb | |||
a60e425d39 | |||
4e3739cdf2 | |||
e51b4700e2 | |||
0b9f7c4c89 | |||
9dcdbbb649 | |||
ac2f0c9896 | |||
fbf5e08425 | |||
df5c264754 | |||
66f535ad61 | |||
b8d84ababb | |||
b485b7a252 | |||
c1395bb543 | |||
0c2e998f69 | |||
504529c3aa | |||
1fab45024b | |||
e354235ebb | |||
d55196352c | |||
45e569845e | |||
b55421d4a1 | |||
fb8da3e4b1 | |||
a9c0f9a165 | |||
4b5c4d58dc | |||
b0e58b5b14 | |||
858c81a19b | |||
04360a35ed | |||
c8ca944fac | |||
b5e4d1a491 | |||
20cb846c95 | |||
a1e531589e | |||
d6b680de48 | |||
28314632bd | |||
09ab904354 | |||
5c0cf60ec1 | |||
698caed9c0 | |||
ae05f5c4b0 | |||
d397bba6b2 | |||
7a6b66e684 | |||
e6daeef55c | |||
c36c1b8992 | |||
1d1f575b5c | |||
ecdffa03f8 | |||
6688184bfd | |||
84a4fd40a0 | |||
d37a195392 | |||
11e76af819 | |||
ed8c0d173e | |||
c57fdbedaf | |||
bd9676aa04 | |||
e5d0a9ecdf | |||
314debb799 | |||
24ad714d0d | |||
41225b53fa | |||
5efd306f7b | |||
ccbcb5c8d3 | |||
2f172d6c5a | |||
1eb81fdf36 | |||
62b6af693d | |||
a49988afbf | |||
03495beadb | |||
079fdbf9bc | |||
002e3840e6 | |||
96c558bec4 | |||
a267263420 | |||
c14fd1ad18 | |||
88782ae43c | |||
70e777d031 | |||
9e1482ad04 | |||
fef08192ad | |||
5488422471 | |||
e8e6dbf839 | |||
5602a09cc6 | |||
164a01e723 | |||
f7f106c42a | |||
7f817fe583 | |||
5e66d95fbd | |||
d064b2e4af | |||
9d067d26da | |||
8e417ecb5c | |||
a9d072ad02 | |||
5630c2e72c | |||
29ff59cc8a | |||
dab429521b | |||
48fc106905 | |||
ee72d5d01d | |||
378f4dd46d | |||
2455f081fc | |||
f06acc4e27 | |||
3c546341e3 | |||
650bd1c179 | |||
9efa96fe0c | |||
361c2ac576 | |||
54359be31a | |||
77949acaee | |||
88a852ef0f | |||
cb52b1757d | |||
b4869d0663 | |||
30fa7b8006 | |||
7793ca4055 | |||
3353a23fcb | |||
b32b9bd1d5 | |||
133a8cea1c | |||
729dbf7dda | |||
67e9ef43a7 | |||
1b5b54fe94 | |||
9b3e6112ff | |||
7663e7dd05 | |||
2e29e64a3f | |||
15e0319c98 | |||
055ca98fb2 | |||
968295ed81 | |||
48e366d7a8 | |||
9aa10ef7ca | |||
a85b8d69ef | |||
2900d51e5d | |||
63cc113f12 | |||
3bf88da091 | |||
11e3122843 | |||
dbe6b1da44 | |||
91dc7776ec | |||
a5036499d2 | |||
9ef4b45609 | |||
5b160f187d | |||
604f17b897 | |||
da1f3bf41e | |||
452acf3a75 | |||
5ad50adaa8 | |||
c165165b58 | |||
0303d315fc | |||
2129257454 | |||
a7e9ce2e33 | |||
b9851cdabe | |||
a9261c6d64 | |||
064131887b | |||
6b5d5b11b0 | |||
3f2859ec16 | |||
5340f2f2eb | |||
8610b0e406 | |||
ffb4767fc1 | |||
97cae2df99 | |||
dc0369eb10 | |||
71f0bd003f | |||
cc65e91eeb | |||
2ae0208d3b | |||
7114663f52 | |||
26e45e41ed | |||
38b14c5c44 | |||
0c76d7e621 | |||
c69c84da09 | |||
0565fe4213 | |||
cb0bc98576 | |||
ef4eeede86 | |||
1cce581ffe | |||
989a85bb05 | |||
db3645c76b | |||
b5c5496b2f | |||
4aec6dabde | |||
0fac7bd373 | |||
9c1c1062be | |||
36a03e3bc8 | |||
dfb0a65e07 | |||
d40866add2 | |||
9ca8ff77f3 | |||
e95ac10ff7 | |||
c7cf2c17a2 | |||
29b1e30126 | |||
24b9eddc7e | |||
effa766d4a | |||
b9783e44a3 | |||
35c817ccd0 | |||
77d68bc7bd | |||
6392a349ce | |||
4489dd24a8 | |||
d374648ce3 | |||
d611e7d50e | |||
25d6d21617 | |||
74b4096570 | |||
eca55be4fb | |||
71372c4d2f | |||
a0693d466c | |||
14d2456c35 | |||
c8bdf0790f | |||
0b8a5cb4bb | |||
8f98d5a8f8 | |||
b83a2c1a00 | |||
5a4d4ad736 | |||
5bc6dccbbd | |||
42ee300e92 | |||
582f5103d9 | |||
abef859925 | |||
6eb79c28d1 | |||
84a096561a | |||
9a1f105869 | |||
677f2c6ca9 | |||
508230e91b | |||
9cab515e58 | |||
514036898f | |||
19415f2554 | |||
710a29a1e0 | |||
c36c34cf9e | |||
e910c224da | |||
ea95453975 | |||
61ea398612 | |||
64e1d3a975 | |||
50fc7327f2 | |||
71edae4a0f | |||
0dd8ed9171 | |||
d568559f01 | |||
1e290542bb | |||
245304f593 | |||
be441dc176 | |||
da1a0249d7 | |||
d07587885c | |||
376b45c199 | |||
b247366c4e | |||
7c383094d9 | |||
9721990507 | |||
452067ffca | |||
3ce5efc44b | |||
1e8c1a4c46 | |||
b53ec1b247 | |||
4ccfbe4e5a | |||
7698c051aa | |||
1950f09bde | |||
e41b03eb30 | |||
98545f30aa | |||
81873d97f8 | |||
cda56ca129 | |||
ab5e0703da | |||
f370ef38c4 | |||
1119a2e185 | |||
9d7ac3d99f | |||
0732e66da9 | |||
e56e2f4c18 | |||
23d9649aec | |||
738a245c3e | |||
78d73720a2 | |||
e59282fe20 | |||
9785b15ed2 | |||
8c94a3d177 | |||
5bd8aa489b | |||
e71c2937de | |||
3d6c58df53 | |||
34c090a31d | |||
762421b355 | |||
b7f3d180aa | |||
71f8cc9dd2 | |||
3c7bc6fd42 | |||
af60844aea | |||
c4c13dd235 | |||
ba4f0186dd | |||
a5c09e4c11 | |||
c7818714ac | |||
cec3d74497 | |||
10b226418c | |||
c843085a28 | |||
101c5a275f | |||
acf4b0981e | |||
98c0908185 | |||
ead3701f5b | |||
0349b0a735 | |||
11cad9fb20 | |||
7f44fec0a5 | |||
d4c8a2058d | |||
d73e63bd70 | |||
48655c2e12 | |||
d0d5518ea8 | |||
822e75f7c2 | |||
08b6b4ec4e | |||
3253e3f315 | |||
e58e54c2db | |||
0a7dc10dd3 | |||
3914aec72f | |||
9b63fc758e | |||
d3130ace30 | |||
daa09a5fbb | |||
a249dadfb0 | |||
64e9f1f3a2 | |||
9110097e11 | |||
ac48b58184 | |||
8f5fb47082 | |||
a58382d3ff | |||
5ef8e3cf29 | |||
6544014ced | |||
3fcb3e2ed3 | |||
caebc9347f | |||
1f257c5875 | |||
e2a3de71ca | |||
57a0134b0c | |||
d9b18ec853 | |||
6c14415664 | |||
567b3985ab | |||
45561d552e | |||
fbd5bd8f37 | |||
048beb752d | |||
87621b6345 | |||
ff14dfc0fc | |||
c624831717 | |||
c697a003d1 | |||
6bdd7a1609 | |||
50a195fe59 | |||
738016952f | |||
209aa25d27 | |||
1279c935e2 | |||
28e5a8031c | |||
f4844e2c0c | |||
ef3a13fa63 | |||
699f769385 | |||
2548b657d8 | |||
02d19dafb2 | |||
78009d9d07 | |||
2aa7ddf1a8 | |||
3c142efecf | |||
23b3e3c84d | |||
8b8600fdab | |||
1938a12222 | |||
4c11ef5d20 | |||
6ac40e2cc5 | |||
5625e059e1 | |||
11767bec0e | |||
7a92bf974d | |||
fc46e9c9a0 | |||
7a752d0795 | |||
0cff53785b | |||
4ad885001a | |||
a0dec909e7 | |||
2a660b19a7 | |||
8992c44c41 | |||
53fd8fe6ea | |||
0059d16731 | |||
18bc344cf5 | |||
e04f4b3f20 | |||
5e389a0970 | |||
1141459607 | |||
02659df6ba | |||
14bd424d2a | |||
7c76b7db04 | |||
a7553eae28 | |||
5cc50bb979 | |||
932eae7343 | |||
604f122819 | |||
d6a7630fe2 | |||
fc4b03ee74 | |||
e9c7610cb7 | |||
3c3a5aa503 | |||
6d3dc83c5d | |||
89512d4e05 | |||
b1d71136b0 | |||
8cf47f2425 | |||
c75b403bb7 | |||
ae284610cf | |||
5a7d33330a | |||
12a9a1001e | |||
97a1af39f7 | |||
6832435326 | |||
62bb94c50b | |||
eeb7e12b9f | |||
f796537712 | |||
469446a02b | |||
b24ef50f7b | |||
f6466214c6 | |||
9c4d32b5b8 | |||
50be709e91 | |||
2e060f856d | |||
c9a2401983 | |||
ce58790fc0 | |||
7f3e04cbc4 | |||
3fb346fe29 | |||
36213dba7d | |||
65817144ac | |||
82432195a8 | |||
77b81e7361 | |||
83f925ccc9 | |||
39208eeb9a | |||
f32d1022bd | |||
ee9447de01 | |||
dcfc24501b | |||
e65e723e03 | |||
94e30002e7 | |||
37603272be | |||
4263519479 | |||
db302ff18b | |||
cbde30e9d4 | |||
c0fd8f4e15 | |||
d39e9ea11c | |||
5b64681867 | |||
0132657432 | |||
aac7c7d75d | |||
bd239d7e3d | |||
da1f2f3c17 | |||
7374af51d1 | |||
38fa2fe0b1 | |||
5a0cc43ee1 | |||
f08a3fedf6 | |||
5cf3426834 | |||
96736309a7 | |||
42ece199c8 | |||
54d01fec43 | |||
f8d717d195 | |||
c6db05c5ae | |||
6f78b67f03 | |||
a5af81506f | |||
087bc6daeb | |||
f18dbb0b40 | |||
6cbd0f1faf | |||
dcd9cd638b | |||
350530f664 | |||
dabce05ec6 | |||
993bf03af9 | |||
2508008b53 | |||
a0012c9e82 | |||
c63956b8ec | |||
6965797286 | |||
5a74cffa0f | |||
f21ff8bac8 | |||
5d932398df | |||
5532fc1102 | |||
60d66ebc0d | |||
29853549c3 | |||
d0b5cd64c3 | |||
cd4243b6ad | |||
cd2be88707 | |||
5b9d306cdf | |||
0fa47bb867 | |||
b22e890ec2 | |||
b6fa63abdf | |||
51a346bcbe | |||
fd9587d26e | |||
0e1d82dd9f | |||
be261b3e69 | |||
f6847b0314 | |||
eca6bdb85d | |||
a3bd1c71ca | |||
b19039ba8b | |||
94a4cc8415 | |||
2e4fda6d4c | |||
cd7e234445 | |||
a5e747af14 | |||
5060861545 | |||
992cf3dd25 | |||
1dee73cdde | |||
3aa7242925 | |||
4009f3a987 | |||
cfd451c6f3 | |||
8e07fbf636 | |||
dae249dc71 | |||
e194acdd79 | |||
287d430fcf | |||
d1d2fceed8 | |||
8cc39a3590 | |||
a57896a7ce | |||
35720304be | |||
09b2565b1b | |||
5b9335be10 | |||
9ce0617cda | |||
61ba214f19 | |||
bfe076748b | |||
070412b9c1 | |||
ccb21a745d | |||
87599de782 | |||
126d1f1cd1 | |||
7685893cdb | |||
f9f163e48f | |||
15ba6249fc | |||
f3799f94bf | |||
e77c431582 | |||
338daa1282 | |||
c616fcafe8 | |||
08fe1e2cd7 | |||
746a2a0ed0 | |||
d2787519e3 | |||
23d0cea3c9 | |||
530bd2b341 | |||
8adc2648f8 | |||
0c45918d54 | |||
288432843b | |||
684f4dd1c4 | |||
d8d89507b5 | |||
f1ef398909 | |||
66e8faaaa9 | |||
f17a3dde1a | |||
88ced831c1 | |||
cc1d6b33b1 | |||
2832cb643d | |||
cd377f3d99 | |||
0def6e3471 | |||
1148a2d0d1 | |||
38d9aedb26 | |||
1467776a3f | |||
f678731234 | |||
e04d2a6efa | |||
1136e887bd | |||
416020daef | |||
73a1b39446 | |||
253bbf3a5c | |||
782cffb130 | |||
a24352ddfd | |||
2f41663673 | |||
cdd1dd3d20 | |||
dea1dbfba4 | |||
988a32ced5 | |||
188a6f5ec5 | |||
aa4050d406 | |||
581097d58d | |||
dba3595c0a | |||
c159b872ef | |||
df74edeb45 | |||
dcf7d85cba | |||
8e953d9931 | |||
9f89bbd5ec | |||
6a6dd84b39 | |||
36ce9c1fb9 | |||
0581f6ec00 | |||
1a582d54e5 | |||
a3161b902e | |||
783f3b0957 | |||
8ff0161d58 | |||
9f7bcca91e | |||
891f6985ed | |||
98ffef26dc | |||
81179b4829 | |||
e7bc3e09a3 | |||
8f93cf5c55 | |||
dc0b2dda5e | |||
ed5d65b54f | |||
172d384bf2 | |||
1e30c3a941 | |||
a10a3f2fa7 | |||
2287534ec6 | |||
27d6d35893 | |||
13429d204d | |||
0d4f2da8db | |||
47fdbf3817 | |||
1d4a3c87f5 | |||
c18f6c2618 | |||
6e8f249b20 | |||
3ac568c40c | |||
90409f383a | |||
cc72f5dfd0 | |||
6d620f5e0c | |||
9d686ba523 | |||
9e5c4973eb | |||
70a67ca67d | |||
e43473faef | |||
38e7dd2b9e | |||
42ce48db39 | |||
445d4b7e59 | |||
05a3418f86 | |||
df46521658 | |||
d559d5a374 | |||
469b8ee022 | |||
385f7da77f | |||
90506479e7 | |||
b2a2b0fc21 | |||
7862416844 | |||
031946136b | |||
7b59e05600 | |||
f6050ab804 | |||
43e97a5aa2 | |||
f0cf9c2cdf | |||
3e0a3ec45f | |||
6865cd8d69 | |||
59b80cb01e | |||
d946be29b9 | |||
95322c11d9 | |||
76ca6adbc5 | |||
45aa579f68 | |||
9ddd7e0e3f | |||
6730b6a15a | |||
6e08be1d0b | |||
0b21441590 | |||
449a14d1d0 | |||
57495a794d | |||
7d0ae2939d | |||
7fa289316a | |||
0e8388d3ea | |||
caa8fea8e2 | |||
212e5d1a72 | |||
713952b9c7 | |||
20b8fc075b | |||
fc77f0bb96 | |||
2eb7d0d88c | |||
41493b1e3f | |||
f526bb2ecb | |||
4e37e12c06 | |||
d83ab141f6 | |||
11236dd545 | |||
bf8a154bec | |||
2b9ecd6eec | |||
3712a70115 | |||
e4f01a6825 | |||
3549cbb3a2 | |||
7c17697cae | |||
0e1d306b2e | |||
70c208ead7 | |||
2d25662b81 | |||
e12edca29a | |||
7e0663e4e0 | |||
4bd736e1a7 | |||
d39830a4dc | |||
d7c9f947ed | |||
84426631b4 | |||
2c9c2e139e | |||
a540bae7a9 | |||
891b568678 | |||
901360b902 | |||
c8295e1485 | |||
9cc8ebd351 | |||
3f6bfbd981 | |||
6fece5525e | |||
28b43ab137 | |||
f807d7cefb | |||
f240c5381a | |||
32281ddcb0 | |||
d23d44a3d5 | |||
dd4c260488 | |||
524d792308 | |||
649a0124d6 | |||
de4f88b4cb | |||
00c1c26bf8 | |||
f4e09634cc | |||
eb05cb4d11 | |||
ec8e8cb51c | |||
249cd2c766 | |||
7323833888 | |||
8904200d48 | |||
7c6a8dc5fc | |||
8bf3093a52 | |||
b2373220e5 | |||
ad79688c5f | |||
50c28dbf92 | |||
7c8cb33848 | |||
e5eb06c78b | |||
d6623d4b65 | |||
04e93d9e3b | |||
76e0381db8 | |||
d375b0e0a3 | |||
97d34b52d7 | |||
0fce34ec16 | |||
42af8ee059 | |||
ed4a70c618 | |||
d49c4d641a | |||
8263f3b171 | |||
0b692faddd | |||
62b17844b9 | |||
8a6544f7f9 | |||
9c1bef49e6 | |||
f9d7ad8e43 | |||
69898722cb | |||
687b357b2d | |||
3beee6da77 | |||
16a7e4ae68 | |||
def4ad645c | |||
ecce840eca | |||
273e3aed10 | |||
2a549d548a | |||
a83691d662 | |||
13296af491 | |||
706718ca2e | |||
a971fc8f36 | |||
0a5929cc85 | |||
2c24cb63a6 | |||
9bdfb04691 | |||
f4dc71bd85 | |||
cdbb35d87e | |||
a32c671ac9 | |||
528193e925 | |||
ac08a38db9 | |||
3e20edf10e | |||
be5032f49e | |||
8330e0e8ba | |||
df55fb1f14 | |||
d606018ddb | |||
20bcd4009b | |||
d6d2a53087 | |||
55e90c0c36 | |||
220804714b | |||
d41f413016 | |||
0ad698ffbf | |||
b670ba182e | |||
e40415cf16 | |||
204059c61a | |||
4cccdb89c0 | |||
b98a5de39b | |||
ef00ed6090 | |||
8acd503526 | |||
4bca8af499 | |||
4d7f39f819 | |||
37f865ab24 | |||
b133fa3b6e | |||
1e679e3cbd | |||
bd1acfd868 | |||
24dcc5eb37 | |||
99b2adcbe2 | |||
12df4c4af7 | |||
ed5a3e92ff | |||
5c35f3dbd1 | |||
afb23f09cf | |||
5a114fd840 | |||
9db58da8b7 | |||
54bbddec60 | |||
a1c54425f7 | |||
e22ba031f5 | |||
08ad02d2b0 | |||
1b758e4d6b | |||
5571142e25 | |||
3b9ac30efa | |||
39be4cd80b | |||
16286e3e2f | |||
bf18987369 | |||
e19e06aba7 | |||
33c18c36db | |||
1a589e2313 | |||
f64f226127 | |||
f47d905225 | |||
34a9419b89 | |||
1bb6e1911b | |||
1dcc6b2e10 | |||
a86f740995 | |||
d84cd978d4 | |||
e2ef242898 | |||
49acc388dd | |||
4e8941950c | |||
312732bdbe | |||
e6685436d8 | |||
5fa4f47bae | |||
4dbb47feb1 | |||
a93e11b797 | |||
0aad26d85e | |||
585c3015a5 | |||
b6209b3732 | |||
079f177cda | |||
ce49ba428b | |||
b5dae8e4f1 | |||
0403f008e3 | |||
96b378d5ba | |||
ff0617f41e | |||
9ea498585c | |||
aa2cb66ea2 | |||
420b1aa859 | |||
f2f6be5e99 | |||
e360726730 | |||
fd8fe4dd08 | |||
1e10e452aa | |||
ea37d8cef9 | |||
7734a9229e | |||
ca35e57eac | |||
369b6d2f67 | |||
0d8f70423a | |||
e5972efa41 | |||
2c7fba0a9c | |||
1ece4bb7df | |||
b219198576 | |||
ff210e824b | |||
95558a2965 | |||
4bcea7b31f | |||
1edc392194 | |||
599f78a4bd | |||
f772d49faf | |||
5fa62e40b1 | |||
ffdbe17037 | |||
fb22ea6a66 | |||
c27ee355e4 | |||
035833cb39 | |||
aa020d70c2 | |||
43b26ca188 | |||
7c506d2e9e | |||
b66543bb29 | |||
0f25a2b434 | |||
026b68c47b | |||
1775c8a6ff | |||
3c8cf0c53f | |||
acaf99cd05 | |||
e2f6114839 | |||
9861213ad6 | |||
f676e5528a | |||
118a81a5fe | |||
56bc55428f | |||
ef56122888 | |||
542bea37fb | |||
1d8e772f6c | |||
0339e737f0 | |||
a1e56fdbed | |||
8908803532 | |||
13ac2cb125 | |||
2fe7889912 | |||
e2eedefc65 | |||
fd03c64346 | |||
fa877b573a | |||
63fe2977da | |||
de2771d126 | |||
37bdda0464 | |||
b4d9d56af4 | |||
9e4ebfd4f6 | |||
c7167190a6 | |||
9e53ae7035 | |||
3b8fe02080 | |||
437efe795a | |||
2d7e3da2cd | |||
d2c4e60115 | |||
2b50f6e0f8 | |||
214868777f | |||
4384008f81 | |||
86a25e64cd | |||
677581bb0f | |||
f2511a39ae | |||
f5d4618702 | |||
4094dcdf88 | |||
3386ea2345 | |||
e2618ab7c1 | |||
9f584e8cd9 | |||
3b4920011b | |||
e5f081586d | |||
0498d6fa89 | |||
1e8ea984d7 | |||
19ebdf31b9 | |||
6e9fce1c2d | |||
f07fc52cd0 | |||
c8581050ff | |||
b15cd4a82a | |||
95a98fb3e8 | |||
b050c11583 | |||
ceed66930e | |||
b13bb64c3b | |||
bb88d98ff8 | |||
465033b04a | |||
04d17ad56e | |||
d3dcc352da | |||
83481f9460 | |||
9bf8f79496 | |||
3823297958 | |||
17f0aad0f0 | |||
3374ada561 | |||
482697039b | |||
fa64c0d4a5 | |||
3561a1b775 | |||
2c6847bfa0 | |||
5d2330f04e | |||
6abe330303 | |||
436873a19a | |||
e7c95ebf5a | |||
a58800b901 | |||
8b17cac71c | |||
c490b9aa36 | |||
7e7ab8f541 | |||
c51f89b58e | |||
9da167dffd | |||
ce0b9dae59 | |||
7ce627c92e | |||
44bf5bf262 | |||
4fbcc37f84 | |||
fb221db8ae | |||
8b92a40e19 | |||
00d086f816 | |||
0d5a8f69e9 | |||
72058fdcbc | |||
b8bad5a227 | |||
274c8d7d3c | |||
f706e210ec | |||
e7770a7002 | |||
99fe0becd4 | |||
0eec622155 | |||
08691fcc97 | |||
db5d501715 | |||
00b1d16ac6 | |||
6b0950b03d | |||
858b5da24e | |||
1ac31361ca | |||
b6c5974b37 | |||
f24135f1ed | |||
55e9297202 | |||
800d43b846 | |||
cb23fe2aba | |||
7c0704b30c | |||
3671d7eb8a | |||
bd58094dbc | |||
b5c19a58f6 | |||
d5dff8960c | |||
e673dc6dbe | |||
d1d5e7c02a | |||
a0e6b98ce8 | |||
d0ea8f8433 | |||
b0492ba642 | |||
4b83b2696e | |||
88d9fba4c7 | |||
7b02847cd6 | |||
f369bf6b80 | |||
a6d6ac2413 | |||
8a44b572fc | |||
781123a906 | |||
553d9f5cfc | |||
1b1e630461 | |||
9a9e92724f | |||
57204c7917 | |||
578b1f4b94 | |||
c7b4a729a9 | |||
48171dc4ad | |||
da42afe32f | |||
f88910755b | |||
d176c59ea2 | |||
b2bee5c32a | |||
2692ef788b | |||
69b4977036 | |||
b95cd8968d | |||
67cbeeb395 | |||
e7fc1ef49e | |||
5fda7861fa | |||
80705aca61 | |||
db2eb75205 | |||
710566be93 | |||
3827b912c7 | |||
345c1deb58 | |||
3f2f232fc5 | |||
49c6f7245e | |||
bfc33150f4 | |||
6dea693441 | |||
3b9517ae73 | |||
842cd9dec3 | |||
4b4effe343 | |||
c3bb0a3421 | |||
878a80de7f | |||
f7e1397d98 | |||
e90fa623d9 | |||
9829c5eb95 | |||
3f23f40a56 | |||
cd2cae720b | |||
65b4141cd3 | |||
58c7a0f8fe | |||
9a2f2f1ee9 | |||
c983e2c5b1 | |||
2eb88d31a4 | |||
0fb68cbbfa | |||
064cd3315c | |||
cc3bf762ec | |||
29bbe0aebe | |||
33ce5829c3 | |||
a05bd3e477 | |||
9ed4bfbca8 | |||
67b6298895 | |||
3122790295 | |||
5aa089d1b2 | |||
b0a2160c3a | |||
4f343e791a | |||
7db87ec74b | |||
8679f3d757 | |||
65bafe7192 | |||
49b3c9e0a0 | |||
e244f85c0b | |||
cc151388a1 | |||
5f0a252fae | |||
d8fb4a8e19 | |||
5e53d337db | |||
b91000fc9e | |||
ce3cd71dc0 | |||
c283487d94 | |||
fe74c68c42 | |||
a521bfdfd8 | |||
d7b6b810d1 | |||
7028c9b59d | |||
891f067051 | |||
939721e2cb | |||
6226e38451 | |||
64435284ce | |||
cf70fe0c9e | |||
7218afdd8e | |||
0627336466 | |||
2b9ad9acb6 | |||
17d364c8a0 | |||
6ccfc2df56 | |||
26d27d9121 | |||
7832daf969 | |||
860bce8a80 | |||
eb61134bed | |||
c5d4e8d0c7 | |||
201287f60f | |||
d0d0405676 | |||
42f992303e | |||
e79a4faf10 | |||
2863d6205b | |||
624f0da6c0 | |||
c3423d81d0 | |||
fc1a52b1c6 | |||
05825a888e | |||
bc6c5d6be2 | |||
6bf9855342 | |||
0db7b39e62 | |||
49c9b68e4e | |||
d40b670388 | |||
01f0af64da | |||
31f7404272 | |||
cb4a20ba6d | |||
8c841a068a | |||
f3fb1d3411 | |||
22452da2a7 | |||
cd165b18f0 | |||
7515e1edb5 | |||
a49384f23c | |||
9b39900c30 | |||
8817c66e98 | |||
2038f86016 | |||
b8b0ba004b | |||
41165c0e68 | |||
30e4e7340e | |||
aa95728c35 | |||
b262c5478c | |||
ef43a4f82e | |||
8bc0b646f0 | |||
65bee44d6d | |||
7d585059e7 | |||
d08504a667 | |||
08f2a35b9b | |||
8e64b13bc0 | |||
983abf359c | |||
233112c9b6 | |||
37dbccb674 | |||
c8524ad363 | |||
30435ee1f5 | |||
ac322253ca | |||
05bb4252bf | |||
e5326e797e | |||
ca203d413f | |||
a1e5a2e607 | |||
674fbc39f8 | |||
948a83ef9f | |||
2b0cfe1ab5 | |||
6b6aa23645 | |||
4231c49839 | |||
ef2dc98773 | |||
984faca4e8 | |||
70ad97d739 | |||
1ab2a0cce9 | |||
c19b6fb260 | |||
dbdd9dbbde | |||
a3416b1571 | |||
e12b71773d | |||
f576c87e3a | |||
c5e231a711 | |||
57334a44c1 | |||
523859f37c | |||
0894f8cf7a | |||
d8234e58a4 | |||
f6a6df7279 | |||
b0d590fef4 | |||
f8bc9b54da | |||
60c8121c1d | |||
124ec8d297 | |||
e9ed056913 | |||
99b0860835 | |||
25b435060c | |||
ba1b04be1e | |||
2ccf5323c2 | |||
891aadaaca | |||
2e07261f57 | |||
5178a0cbba | |||
8d5fded4d8 | |||
8e85b9cbf3 | |||
d4da9b805a | |||
ae4f770dad | |||
cbe38ff905 | |||
9c2e27a026 | |||
644bdd220e | |||
93a9e2daf3 | |||
b2896c79c6 | |||
8c0d247126 | |||
39dc0cca37 | |||
7f0fe3b7d2 | |||
2f209414ef | |||
ccb156c704 | |||
8a2f2e1792 | |||
79490e75be | |||
e8b576fb9f | |||
d96b27b603 | |||
c8d94e88a7 | |||
f3a23e51fa | |||
7e022a09cc | |||
b6e51a5cd6 | |||
a8f6ce5475 | |||
c96efdcb36 | |||
55ef73ed57 | |||
4b3deaf28b | |||
d8264390d2 | |||
0071e537f3 | |||
5efd936e1e | |||
c8c004d568 | |||
a9972fe559 | |||
1f7f9fa9ec | |||
a9d0cad485 | |||
f85b0d421a | |||
88384c89f3 | |||
22cfd595ef | |||
e235c02e1e | |||
02548197e8 | |||
c2ba6e4503 | |||
7f017aa724 | |||
d51719fbd9 | |||
1392a6dba7 | |||
7413ca9589 | |||
2b1e56331d | |||
cc5e69816f | |||
c59e07581d | |||
c15053d1f8 | |||
5939727b66 | |||
3ceb679465 | |||
8f188194c1 | |||
760d4991f3 | |||
613ab3ba2a | |||
9477967c54 | |||
388f4ae302 | |||
f1fbea96f6 | |||
f0aaee2044 | |||
ac7d210b6b | |||
659db7e421 | |||
cd84339bcc | |||
01d5537244 | |||
ab8fb271f7 | |||
58a18ea50b | |||
574de9ff4c | |||
9d8458bb6d | |||
b22145d0c4 | |||
99e623ef0b | |||
7a20cc2f58 | |||
8290bb3374 | |||
a3932d7f00 | |||
8082dd43bc | |||
642a756b66 | |||
f6c44a83bc | |||
b92da08ae8 | |||
499f078c37 | |||
92669e65ee | |||
7b82ef22be | |||
3ce808688f | |||
cc301c18d5 | |||
db7c990346 | |||
7c99027c31 | |||
5cb0012c83 | |||
a09cfd57a4 | |||
62d9729629 | |||
ed16281737 | |||
4d9a463297 | |||
e13fdfb2ce | |||
73cb587266 | |||
48388b9eaa | |||
61e46a636c | |||
dede2e9764 | |||
c9c7e4777e | |||
67ae54c957 | |||
14c359700b | |||
c11b8883e0 | |||
adae07d013 | |||
1c7b6a5e05 | |||
fbeba570e6 | |||
c3b2fee074 | |||
e2442f7471 | |||
b33bb0943a | |||
58fe2f2c76 | |||
664f603a31 | |||
b17afc10a2 | |||
74f7576313 | |||
e8d0ffa8b4 | |||
ceb2d99732 | |||
822a3e505a | |||
7b0ab778e3 | |||
744910ad1b | |||
7fdc7e01a5 | |||
c7c622377a | |||
ae990ce8dc | |||
7ab2e1d184 | |||
c21b78b297 | |||
94a7102d3a | |||
fce7a0c78c | |||
98b27d0c64 | |||
2d0b90b423 | |||
070ccae4dd | |||
4620d31e2a | |||
16953b5cfa | |||
cfccadcdc4 | |||
67533cf7c3 | |||
8a10f3f22f | |||
c87210820c | |||
66791a5dad | |||
ee9b2522a3 | |||
df5c7eef39 | |||
ccbb0d37b3 | |||
66f123fb66 | |||
87b599f4a8 | |||
6238df88a2 | |||
38d74f0ad5 | |||
25443918c4 | |||
8035968516 | |||
f9bf0bd90e | |||
0df37d0fa1 | |||
fbb131da73 | |||
942f8d0ec9 | |||
64fa11d204 | |||
3ad5316dd1 | |||
f8e0e9ab1f | |||
10af76a50c | |||
2fafb9f2fb | |||
4de38fe40a | |||
74df3e2491 | |||
8e41a59e2e | |||
17729ce856 | |||
cfd7b906cb | |||
a1f7de2bc3 | |||
f2b3f01759 | |||
3eaf5560be | |||
c66633ccc5 | |||
a2f911dbb1 | |||
060579b73a | |||
09c26fed20 | |||
3e9e7e1750 | |||
94548d2284 | |||
4ec4e5b394 | |||
15c920a612 | |||
e7871b2c76 | |||
644efa2905 | |||
7e9b6fe0aa | |||
b8abf27b86 | |||
e0ff20dd37 | |||
0af42727f5 | |||
b0036759fa | |||
b4b26d4207 | |||
cb7ada2e78 | |||
6e5143681c | |||
8142422257 | |||
0f03226656 | |||
297e9e3cf5 | |||
39b7f48870 | |||
b9bc81544a | |||
7d9eed0ed5 | |||
1398d8d5a6 | |||
6bc874088f | |||
3ec1baee65 | |||
374f661027 | |||
7ab11c3da9 | |||
cc2f3afdf8 | |||
9a5882a290 | |||
a033364d55 | |||
bc3ce26e0e | |||
ebea44029e | |||
be6bc155eb | |||
d0bbef74ef | |||
a282ae22af | |||
c83e8e1e62 | |||
452ec28761 | |||
8a78637719 | |||
1fdb75068d | |||
230c135d4e | |||
bf544af690 | |||
e7ab8be0cd | |||
b1822f2602 | |||
f4a74a3405 | |||
73da639654 | |||
f2a1456e94 | |||
c75abda571 | |||
1aec670c43 | |||
77695d75bb | |||
3dec452a8a | |||
97f5ce52d1 | |||
540de896e3 | |||
dcfccb2a0d | |||
ac5b0a3b34 | |||
8f854ee83a | |||
bd312607a3 | |||
99f2abfd71 | |||
132ecc0580 | |||
5157a56803 | |||
33281b04e7 | |||
a9404fe33f | |||
95bdb47f01 | |||
ebf624772a | |||
b33a6addcc | |||
1e4fb1f6fe | |||
287828fe0b | |||
dc311b978e | |||
bccaf93f8b | |||
61a84e15ea | |||
f7bdb6555d | |||
4183bc35b2 | |||
4700800770 | |||
9de74cce92 | |||
125a59df91 | |||
eae4a9e1f8 | |||
20f009e927 | |||
78d9fa280c | |||
45bb85cd8f | |||
16551643b3 | |||
5245ed2262 | |||
9e91b15b74 | |||
b5c2646360 | |||
8cd7f3438f | |||
e0ff431169 | |||
a8ff64f704 | |||
9c105098dd | |||
9af6395e92 | |||
670316f997 | |||
4cf02a32a7 | |||
6b3a9b9dc0 | |||
d544a5a947 | |||
973b0ac488 | |||
baff2ce80f | |||
8a7fed5dfb | |||
a962359993 | |||
5b45fc5921 | |||
c8d3d813ff | |||
8eafa90105 | |||
8e2ee30c47 | |||
19afe50efa | |||
8f519e7959 | |||
293ff9d586 | |||
2109d37298 | |||
fb31a3bf2e | |||
68fa95beb3 | |||
942245b985 | |||
6e25fde883 | |||
46955be305 | |||
b89d10025d | |||
edb33cba0c | |||
783e5fa42f | |||
9c31196610 | |||
ca765b5ebb | |||
3f65f534aa | |||
1fc328b2ea | |||
1e93146b49 | |||
36fea4ba7b | |||
18a1a19deb | |||
1d52e1f41b | |||
f0ec7635ab | |||
158d8a181e | |||
f66c0a5d98 | |||
a609b08c0a | |||
e63c9ec05e | |||
4936322dbc | |||
9baee07c94 | |||
03ecf6e695 | |||
2b1b9f816c | |||
1b55df5848 | |||
7bec9e3804 | |||
06cb695cd7 | |||
c08f4f5845 | |||
c71fc74248 | |||
0b52d342f6 | |||
a5acd32f56 | |||
a7e45319c3 | |||
e18caef4f6 | |||
149b7d9ee8 | |||
d13592aea0 | |||
59d4b0aadb | |||
96c9fa0ccc | |||
7cdd0abfd5 | |||
74ef58e310 | |||
897fb9c2e4 | |||
ff1f6af7e9 | |||
9aefe7a040 | |||
17bb51756f | |||
5044bb0332 | |||
b4ca95a9fa | |||
f097f780af | |||
99be294726 | |||
7adb7cf7f6 | |||
e36e5f4fc9 | |||
1e503a586d | |||
6488400fbf | |||
e423e0a0f1 | |||
ad1750b53d | |||
e909d5f5c2 | |||
6e6480c952 | |||
ff5c7b155c | |||
123d97bfb8 | |||
dd0a8c200c | |||
272a43be11 | |||
63677bb1f9 | |||
780a78c825 | |||
c29af4aeba | |||
48e6e3ac45 | |||
74a984d75f | |||
b55ea6409d | |||
68b3849d51 | |||
ed7917e619 | |||
5e56d3bf36 | |||
e2dfac08c0 | |||
c8173eb9ec | |||
832c784a70 | |||
61b0a3775b | |||
5f50964176 | |||
428b88a82a | |||
46ac559003 | |||
caba176c87 | |||
f37e7c5240 | |||
252742ce20 | |||
3f3f03f715 | |||
4df1ad35b3 | |||
4e87c6af02 | |||
fc277b736a | |||
278f4fd08e | |||
df86816e7d | |||
d8059cab6b | |||
d1a2a3eee5 | |||
7856f09799 | |||
461e717157 | |||
8ee11fecc4 | |||
36020c41df | |||
6444bc6a71 | |||
a67d86c6e2 | |||
924f3025f9 | |||
9690bb4b9c | |||
5d5ee85928 | |||
820621baa2 | |||
75d2881302 | |||
95b641198e | |||
6b40189045 | |||
df379dfcf4 | |||
4721617fd6 | |||
b82ff2d7e7 | |||
efa2052896 | |||
52cbd650b7 | |||
4cb1d756f7 | |||
84161d7c9d | |||
c8c5ec254a | |||
1a0b491ed6 | |||
3a4226a28b | |||
1a47a5a739 | |||
760416c1a0 | |||
5955dd4e25 | |||
e0f9aa3508 | |||
b31dff6bee | |||
1b3f971330 | |||
abf61ecc8f | |||
71bf2d8826 | |||
52bfd1fc3d | |||
a8d96967c4 | |||
f7a400878a | |||
e1f18f6212 | |||
9705ccee67 | |||
7151651ea9 | |||
0d7ecd4327 | |||
50530c144e | |||
45f00e45be | |||
e969afc627 | |||
f094908f54 | |||
f3617bd83b | |||
3bfd88aabb | |||
d47ef88fcd | |||
b24639d011 | |||
2ae4ca91b4 | |||
e9d968e060 | |||
1652831f1d | |||
39c4bb7a49 | |||
6cb07a9131 | |||
e76ad2980f | |||
af5fd8c819 | |||
3b3df4e3cb | |||
c124576a4d | |||
659037eef5 | |||
500a378fdf | |||
4f3c417753 | |||
113fc168ab | |||
0ba49eacc9 | |||
bbd9441fc6 | |||
22454ce60b | |||
5036cb54cc | |||
2eeb07d164 | |||
ca6ac09dcc | |||
eadd378f6c | |||
7b36afd5f1 | |||
f677427f68 | |||
132ad08885 | |||
d3e173b6e6 | |||
3f2a317af0 | |||
892513708b | |||
733c8e4c34 | |||
80f175daac | |||
c5e0b29a22 | |||
bec9b307db | |||
aca63d4986 | |||
bae398a9a4 | |||
0d001c09c3 | |||
cd259fe118 | |||
d7b707a71c | |||
17228d27e5 | |||
10df5ad0ac | |||
7338568125 | |||
4adca18337 | |||
b6f5e1635c | |||
0e59a59169 | |||
6b45deaf97 | |||
e72d4a96bf | |||
b79adc01fa | |||
790d717543 | |||
b1ebd62c78 | |||
fcc349467f | |||
cc55e5c6d8 | |||
a51d4227b6 | |||
742aed4f2e | |||
d3d0682310 | |||
53012ff41c | |||
dd734a01dc | |||
2053731ebc | |||
a3b863d312 | |||
7cb0658b00 | |||
96c76a8333 | |||
925cfba424 | |||
f63318a20f | |||
f5d4912ca8 | |||
642cf8b5ff | |||
0612aa2b65 | |||
3937764ac5 | |||
ed603dcba2 | |||
41d2e7d6b6 | |||
73d02f3a80 | |||
e1183be22e | |||
2971b5b315 | |||
65a3a9773d | |||
8b6a4e5759 | |||
07df1e3034 | |||
09c95b7ea7 | |||
a6fe8ae0af | |||
dc2c46e23c | |||
0f476a289f | |||
ae3f058ff0 | |||
1315021388 | |||
ccb231e4f4 | |||
aad485128e | |||
54bb9f4b55 | |||
af823d6486 | |||
487a87df02 | |||
b14fead592 | |||
ebf2c8caa5 | |||
84855737b3 | |||
7a608d1346 | |||
3e418ecb6e | |||
89769c836f | |||
7c8470b1dc | |||
81bab528b2 | |||
d6beac5235 | |||
a949b40d11 | |||
7ca22cd552 | |||
30586e634d | |||
2b6fe347ae | |||
f97409dd2d | |||
c384367f17 | |||
eea1c6606c | |||
8f4f45c524 | |||
db2392b778 | |||
ce842648ae | |||
ad1c4bf202 | |||
5969b7cdbc | |||
6013d20aef | |||
dfb3bd8e33 | |||
d6c2db9620 | |||
00dc8a0ad5 | |||
9246f21f2a | |||
2237319ebb | |||
6fa95008bc | |||
3789a56225 | |||
0a2d9af2a1 | |||
2b7a627181 | |||
f697752b52 | |||
914426d887 | |||
302e717790 | |||
27928fbc94 | |||
253056b932 | |||
1d1d0d9b6f | |||
c7887abb64 | |||
47525f0dd6 | |||
5ac5d91c6b | |||
322b5a736b | |||
907c054142 | |||
7b6d51a9d0 | |||
d3eba93c7d | |||
866e22355c | |||
fe084b9866 | |||
5f7e3025d9 | |||
13b8bc1a89 | |||
054cec8a5d | |||
8dc326e1f1 | |||
81dd1aea82 | |||
5b2cb426be | |||
5fa19f2801 | |||
4f5acb8f52 | |||
cf71c53559 | |||
80c98f4d0c | |||
73f8ab3aa8 | |||
da372335bf | |||
0af9f664db | |||
995eb0cd79 | |||
9f07965876 | |||
8a4cdd56d4 | |||
3252523823 | |||
2628f9f61b | |||
0d217e15d5 | |||
520c85c7b7 | |||
82d70e0720 | |||
054976c390 | |||
da8e03e18a | |||
4a80dbdd10 | |||
013a1731d5 | |||
e664024853 | |||
495f3b9a68 | |||
98a6963911 | |||
c204efaaab | |||
0f13137616 | |||
864056fcaa | |||
5c0830f628 | |||
e96a2dd681 | |||
f45332e1ab | |||
5508e30854 | |||
3e14d63a0a | |||
eddfddccb2 | |||
c067ef0216 | |||
f7d9019b8c | |||
519678192f | |||
c3083a77d4 | |||
891ab3951b | |||
11251c77ca | |||
71e22d9263 | |||
3095d96715 | |||
198946231c | |||
b2f0b6f2b4 | |||
d9c70c7b8c | |||
7ae61e7393 | |||
984ae35948 | |||
0d6cddda4d | |||
18e031d346 | |||
c0332ad98b | |||
7f6aaa5314 | |||
14aa5fe521 | |||
9199967022 | |||
04c92c8470 | |||
00b22e37df | |||
aaa810c64a | |||
b57b2073ac | |||
771a9e9cd2 | |||
cc48f4499a | |||
3e2f2ddb56 | |||
0ca6df6f09 | |||
37a379f959 | |||
625d6c2ed7 | |||
c2edb3e22f | |||
fedbd54325 | |||
134d2bd766 | |||
9eb2cd7327 | |||
c0347c80b2 | |||
d9ff84e39e | |||
7256e6d203 | |||
c083fd895c | |||
0cd7a3d216 | |||
aa4fc44a80 | |||
f07d49e877 | |||
45be91ff48 | |||
c657b3d072 | |||
5dfb3ded17 | |||
0104e99caa | |||
e16593c9b1 | |||
1cc69df0f4 | |||
2db576f52b | |||
421edce623 | |||
549b83504f | |||
d10ebd1a68 | |||
4e3d921f1a | |||
1d6e1ec61c | |||
db3cc11195 | |||
d64efa6a68 | |||
7b5905bda6 | |||
f5ba5ffe80 | |||
0113c4f834 | |||
1c2ed83960 | |||
7a236b11b8 | |||
a0328bbcf8 | |||
46e58b434a | |||
7955f8a7cb | |||
263fd37590 | |||
ba37bf13d6 | |||
b59d71546b |
148
.clang-format
Normal file
148
.clang-format
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
144
.custom-format.py
Executable file
144
.custom-format.py
Executable file
@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# american fuzzy lop++ - custom code formatter
|
||||
# --------------------------------------------
|
||||
#
|
||||
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
#
|
||||
# Copyright 2015, 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
|
||||
#
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
|
||||
|
||||
with open(".clang-format") as f:
|
||||
fmt = f.read()
|
||||
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
|
||||
if CLANG_FORMAT_BIN is None:
|
||||
o = 0
|
||||
try:
|
||||
p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
|
||||
o, _ = p.communicate()
|
||||
o = str(o, "utf-8")
|
||||
o = re.sub(r".*ersion ", "", o)
|
||||
# o = o[len("clang-format version "):].strip()
|
||||
o = o[: o.find(".")]
|
||||
o = int(o)
|
||||
except:
|
||||
print("clang-format-11 is needed. Aborted.")
|
||||
exit(1)
|
||||
# if o < 7:
|
||||
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-7'
|
||||
# elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-8'
|
||||
# elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-9'
|
||||
# elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
|
||||
# CLANG_FORMAT_BIN = 'clang-format-11'
|
||||
# else:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = "clang-format-11"
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
line = line.split(":")
|
||||
if line[0].strip() == "ColumnLimit":
|
||||
COLUMN_LIMIT = int(line[1].strip())
|
||||
|
||||
|
||||
def custom_format(filename):
|
||||
p = subprocess.Popen([CLANG_FORMAT_BIN, filename], stdout=subprocess.PIPE)
|
||||
src, _ = p.communicate()
|
||||
src = str(src, "utf-8")
|
||||
|
||||
in_define = False
|
||||
last_line = None
|
||||
out = ""
|
||||
|
||||
for line in src.split("\n"):
|
||||
if line.lstrip().startswith("#"):
|
||||
if line[line.find("#") + 1 :].lstrip().startswith("define"):
|
||||
in_define = True
|
||||
|
||||
if (
|
||||
"/*" in line
|
||||
and not line.strip().startswith("/*")
|
||||
and line.endswith("*/")
|
||||
and len(line) < (COLUMN_LIMIT - 2)
|
||||
):
|
||||
cmt_start = line.rfind("/*")
|
||||
line = (
|
||||
line[:cmt_start]
|
||||
+ " " * (COLUMN_LIMIT - 2 - len(line))
|
||||
+ line[cmt_start:]
|
||||
)
|
||||
|
||||
define_padding = 0
|
||||
if last_line is not None and in_define and last_line.endswith("\\"):
|
||||
last_line = last_line[:-1]
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
|
||||
|
||||
if (
|
||||
last_line is not None
|
||||
and last_line.strip().endswith("{")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif (
|
||||
last_line is not None
|
||||
and last_line.strip().startswith("}")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif (
|
||||
line.strip().startswith("}")
|
||||
and last_line is not None
|
||||
and last_line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
|
||||
if not line.endswith("\\"):
|
||||
in_define = False
|
||||
|
||||
out += line + "\n"
|
||||
last_line = line
|
||||
|
||||
return out
|
||||
|
||||
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print("Usage: ./format.py [-i] <filename>")
|
||||
print()
|
||||
print(" The -i option, if specified, let the script to modify in-place")
|
||||
print(" the source files. By default the results are written to stdout.")
|
||||
print()
|
||||
exit(1)
|
||||
|
||||
in_place = False
|
||||
if args[0] == "-i":
|
||||
in_place = True
|
||||
args = args[1:]
|
||||
|
||||
for filename in args:
|
||||
code = custom_format(filename)
|
||||
if in_place:
|
||||
with open(filename, "w") as f:
|
||||
f.write(code)
|
||||
else:
|
||||
print(code)
|
65
.dockerignore
Normal file
65
.dockerignore
Normal file
@ -0,0 +1,65 @@
|
||||
.test
|
||||
.test2
|
||||
.sync_tmp
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
ld
|
||||
in
|
||||
out
|
||||
core*
|
||||
afl-analyze
|
||||
afl-as
|
||||
afl-clang
|
||||
afl-clang\+\+
|
||||
afl-clang-fast
|
||||
afl-clang-fast\+\+
|
||||
afl-clang-lto
|
||||
afl-clang-lto\+\+
|
||||
afl-fuzz
|
||||
afl-g\+\+
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-g\+\+-fast
|
||||
afl-gotcpu
|
||||
afl-ld
|
||||
afl-ld-lto
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-tmin
|
||||
afl-analyze.8
|
||||
afl-as.8
|
||||
afl-clang-fast\+\+.8
|
||||
afl-clang-fast.8
|
||||
afl-clang-lto.8
|
||||
afl-clang-lto\+\+.8
|
||||
afl-cmin.8
|
||||
afl-cmin.bash.8
|
||||
afl-fuzz.8
|
||||
afl-gcc.8
|
||||
afl-gcc-fast.8
|
||||
afl-g\+\+-fast.8
|
||||
afl-gotcpu.8
|
||||
afl-plot.8
|
||||
afl-showmap.8
|
||||
afl-system-config.8
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output
|
||||
unicorn_mode/unicornafl
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
test/unittests/unit_rand
|
||||
test/unittests/unit_hash
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: AFLplusplusEU
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
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.
|
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
25
.github/workflows/build_aflplusplus_docker.yaml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Publish Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
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
|
30
.github/workflows/ci.yml
vendored
Normal file
30
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
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: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- 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 ninja-build
|
||||
- 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
|
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal file
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Rust Custom Mutators
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Rust Custom Mutator Support
|
||||
runs-on: '${{ matrix.os }}'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: custom_mutators/rust
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Rust Toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Check Code Compiles
|
||||
run: cargo check
|
||||
- name: Run General Tests
|
||||
run: cargo test
|
||||
- name: Run Tests for afl_internals feature flag
|
||||
run: cd custom_mutator && cargo test --features=afl_internals
|
88
.gitignore
vendored
Normal file
88
.gitignore
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
.test
|
||||
.test2
|
||||
.sync_tmp
|
||||
.vscode
|
||||
*.o
|
||||
*.so
|
||||
*.swp
|
||||
*.pyc
|
||||
*.dSYM
|
||||
as
|
||||
a.out
|
||||
ld
|
||||
in
|
||||
out
|
||||
core*
|
||||
compile_commands.json
|
||||
afl-analyze
|
||||
afl-as
|
||||
afl-clang
|
||||
afl-clang++
|
||||
afl-clang-fast
|
||||
afl-clang-fast++
|
||||
afl-clang-lto
|
||||
afl-clang-lto++
|
||||
afl-fuzz
|
||||
afl-g++
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-g++-fast
|
||||
afl-gotcpu
|
||||
afl-ld
|
||||
afl-ld-lto
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-tmin
|
||||
afl-analyze.8
|
||||
afl-as.8
|
||||
afl-clang-fast++.8
|
||||
afl-clang-fast.8
|
||||
afl-clang-lto.8
|
||||
afl-clang-lto++.8
|
||||
afl-cmin.8
|
||||
afl-cmin.bash.8
|
||||
afl-fuzz.8
|
||||
afl-c++.8
|
||||
afl-cc.8
|
||||
afl-gcc.8
|
||||
afl-g++.8
|
||||
afl-gcc-fast.8
|
||||
afl-g++-fast.8
|
||||
afl-gotcpu.8
|
||||
afl-plot.8
|
||||
afl-showmap.8
|
||||
afl-system-config.8
|
||||
afl-tmin.8
|
||||
afl-whatsup.8
|
||||
afl-c++
|
||||
afl-cc
|
||||
afl-lto
|
||||
afl-lto++
|
||||
afl-lto++.8
|
||||
afl-lto.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
qemu_mode/qemu-*
|
||||
qemu_mode/qemuafl
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
test/unittests/unit_rand
|
||||
test/unittests/unit_hash
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
examples/afl_frida/afl-frida
|
||||
examples/afl_frida/libtestinstr.so
|
||||
examples/afl_frida/frida-gum-example.c
|
||||
examples/afl_frida/frida-gum.h
|
||||
examples/aflpp_driver/libAFLDriver.a
|
||||
examples/aflpp_driver/libAFLQemuDriver.a
|
||||
libAFLDriver.a
|
||||
libAFLQemuDriver.a
|
||||
test/.afl_performance
|
||||
gmon.out
|
||||
afl-frida-trace.so
|
||||
utils/afl_network_proxy/afl-network-client
|
||||
utils/afl_network_proxy/afl-network-server
|
||||
*.o.tmp
|
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
[submodule "unicorn_mode/unicornafl"]
|
||||
path = unicorn_mode/unicornafl
|
||||
url = https://github.com/AFLplusplus/unicornafl
|
||||
[submodule "custom_mutators/grammar_mutator"]
|
||||
path = custom_mutators/grammar_mutator/grammar_mutator
|
||||
url = https://github.com/AFLplusplus/Grammar-Mutator
|
||||
[submodule "qemu_mode/qemuafl"]
|
||||
path = qemu_mode/qemuafl
|
||||
url = https://github.com/AFLplusplus/qemuafl
|
406
Android.bp
Normal file
406
Android.bp
Normal file
@ -0,0 +1,406 @@
|
||||
cc_defaults {
|
||||
name: "afl-defaults",
|
||||
|
||||
local_include_dirs: [
|
||||
"include",
|
||||
"instrumentation",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-flto=full",
|
||||
"-funroll-loops",
|
||||
"-Wno-pointer-sign",
|
||||
"-Wno-pointer-arith",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-function",
|
||||
"-Wno-format",
|
||||
"-Wno-user-defined-warnings",
|
||||
"-DAFL_LLVM_USE_TRACE_PC=1",
|
||||
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
|
||||
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
|
||||
"-D__USE_GNU",
|
||||
"-DDEBUG_BUILD",
|
||||
"-U_FORTIFY_SOURCE",
|
||||
"-ggdb3",
|
||||
"-g",
|
||||
"-O0",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-fPIC",
|
||||
],
|
||||
|
||||
target: {
|
||||
android_arm64: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_arm: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_x86_64: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
android_x86: {
|
||||
cflags: [
|
||||
"-D__ANDROID__",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-fuzz",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
host_supported: true,
|
||||
compile_multilib: "64",
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-fuzz*.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-showmap",
|
||||
static_executable: true,
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-showmap.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-tmin",
|
||||
static_executable: true,
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-tmin.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-analyze",
|
||||
static_executable: true,
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-analyze.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-gotcpu",
|
||||
static_executable: true,
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-gotcpu.c",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "afl-cc",
|
||||
static_executable: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
"-DAFL_CLANG_FLTO=\"-flto=full\"",
|
||||
"-DUSE_BINDIR=1",
|
||||
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
|
||||
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
|
||||
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
|
||||
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
|
||||
"-DLLVM_LTO=1",
|
||||
"-DLLVM_MAJOR=11",
|
||||
"-DLLVM_MINOR=2",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-cc.c",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
|
||||
symlinks: [
|
||||
"afl-clang-fast",
|
||||
"afl-clang-fast++",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "afl-llvm-rt",
|
||||
compile_multilib: "64",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
recovery_available: true,
|
||||
sdk_version: "9",
|
||||
|
||||
apex_available: [
|
||||
"com.android.adbd",
|
||||
"com.android.appsearch",
|
||||
"com.android.art",
|
||||
"com.android.bluetooth.updatable",
|
||||
"com.android.cellbroadcast",
|
||||
"com.android.conscrypt",
|
||||
"com.android.extservices",
|
||||
"com.android.cronet",
|
||||
"com.android.neuralnetworks",
|
||||
"com.android.media",
|
||||
"com.android.media.swcodec",
|
||||
"com.android.mediaprovider",
|
||||
"com.android.permission",
|
||||
"com.android.runtime",
|
||||
"com.android.resolv",
|
||||
"com.android.tethering",
|
||||
"com.android.wifi",
|
||||
"com.android.sdkext",
|
||||
"com.android.os.statsd",
|
||||
"//any",
|
||||
],
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"instrumentation/afl-compiler-rt.o.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libafl_headers",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
"instrumentation",
|
||||
],
|
||||
}
|
||||
|
||||
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",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "afl-fuzz-32",
|
||||
sanitize: {
|
||||
never: true,
|
||||
},
|
||||
host_supported: true,
|
||||
compile_multilib: "32",
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-fuzz*.c",
|
||||
"src/afl-common.c",
|
||||
"src/afl-sharedmem.c",
|
||||
"src/afl-forkserver.c",
|
||||
"src/afl-performance.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "afl-cc-32",
|
||||
compile_multilib: "32",
|
||||
static_executable: true,
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
|
||||
"-DAFL_CLANG_FLTO=\"-flto=full\"",
|
||||
"-DUSE_BINDIR=1",
|
||||
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
|
||||
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
|
||||
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
|
||||
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
|
||||
"-DLLVM_LTO=1",
|
||||
"-DLLVM_MAJOR=11",
|
||||
"-DLLVM_MINOR=2",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/afl-cc.c",
|
||||
"src/afl-common.c",
|
||||
],
|
||||
|
||||
symlinks: [
|
||||
"afl-clang-fast-32",
|
||||
"afl-clang-fast++-32",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "afl-llvm-rt-32",
|
||||
compile_multilib: "32",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
recovery_available: true,
|
||||
sdk_version: "9",
|
||||
|
||||
apex_available: [
|
||||
"com.android.adbd",
|
||||
"com.android.appsearch",
|
||||
"com.android.art",
|
||||
"com.android.bluetooth.updatable",
|
||||
"com.android.cellbroadcast",
|
||||
"com.android.conscrypt",
|
||||
"com.android.extservices",
|
||||
"com.android.cronet",
|
||||
"com.android.neuralnetworks",
|
||||
"com.android.media",
|
||||
"com.android.media.swcodec",
|
||||
"com.android.mediaprovider",
|
||||
"com.android.permission",
|
||||
"com.android.runtime",
|
||||
"com.android.resolv",
|
||||
"com.android.tethering",
|
||||
"com.android.wifi",
|
||||
"com.android.sdkext",
|
||||
"com.android.os.statsd",
|
||||
"//any",
|
||||
],
|
||||
|
||||
defaults: [
|
||||
"afl-defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"instrumentation/afl-compiler-rt.o.c",
|
||||
],
|
||||
}
|
||||
|
||||
cc_prebuilt_library_static {
|
||||
name: "libfrida-gum-32",
|
||||
compile_multilib: "32",
|
||||
strip: {
|
||||
none: true,
|
||||
},
|
||||
|
||||
srcs: [
|
||||
"utils/afl_frida/android/arm/libfrida-gum.a",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"utils/afl_frida/android/arm",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"custom_mutators",
|
||||
]
|
24
CONTRIBUTING.md
Normal file
24
CONTRIBUTING.md
Normal file
@ -0,0 +1,24 @@
|
||||
# How to submit a Pull Request to AFLplusplus
|
||||
|
||||
All contributions (pull requests) must be made against our `dev` branch.
|
||||
|
||||
Each modified source file, before merging, must be formatted.
|
||||
|
||||
```
|
||||
make code-format
|
||||
```
|
||||
|
||||
This should be fine if you modified one of the files already present in the
|
||||
project, or added a file in a directory we already format, otherwise run:
|
||||
|
||||
```
|
||||
./.custom-format.py -i file-that-you-have-created.c
|
||||
```
|
||||
|
||||
Regarding the coding style, please follow the AFL style.
|
||||
No camel case at all and use AFL's macros wherever possible
|
||||
(e.g. WARNF, FATAL, MAP_SIZE, ...).
|
||||
|
||||
Remember that AFLplusplus has to build and run on many platforms, so
|
||||
generalize your Makefiles/GNUmakefile (or your patches to our pre-existing
|
||||
Makefiles) to be as generic as possible.
|
1
Changelog.md
Symbolic link
1
Changelog.md
Symbolic link
@ -0,0 +1 @@
|
||||
docs/Changelog.md
|
73
Dockerfile
Normal file
73
Dockerfile
Normal file
@ -0,0 +1,73 @@
|
||||
#
|
||||
# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and
|
||||
# installs LLVM 11 from llvm.org for afl-clang-lto support :-)
|
||||
# It also installs gcc/g++ 10 from the Ubuntu development platform
|
||||
# since focal has gcc-10 but not g++-10 ...
|
||||
#
|
||||
|
||||
FROM ubuntu:20.04 AS aflplusplus
|
||||
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
|
||||
LABEL "about"="AFLplusplus docker image"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
env NO_ARCH_OPT 1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
automake \
|
||||
ninja-build \
|
||||
bison flex \
|
||||
build-essential \
|
||||
git \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
wget vim jupp nano bash-completion less \
|
||||
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||
libpixman-1-dev \
|
||||
gnuplot-nox \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
|
||||
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
|
||||
RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
|
||||
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
|
||||
|
||||
RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \
|
||||
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
|
||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-12
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
ENV AFL_TRY_AFFINITY=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
RUN cd /afl-cov && make install && cd ..
|
||||
|
||||
COPY . /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
|
||||
RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
|
||||
make distrib && make install && make clean
|
||||
|
||||
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
|
||||
RUN echo '. /etc/bash_completion' >> ~/.bashrc
|
||||
RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
|
||||
RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
|
||||
ENV IS_DOCKER="1"
|
||||
|
||||
# Disabled until we have the container ready
|
||||
#COPY --from=aflplusplus/afl-dyninst /usr/local/lib/libdyninstAPI_RT.so /usr/local/lib/libdyninstAPI_RT.so
|
||||
#COPY --from=aflplusplus/afl-dyninst /afl-dyninst/libAflDyninst.so /usr/local/lib/libAflDyninst.so
|
676
GNUmakefile
Normal file
676
GNUmakefile
Normal file
@ -0,0 +1,676 @@
|
||||
#
|
||||
# american fuzzy lop++ - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
# the hash character is treated differently in different make versions
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
ARCH = $(shell uname -m)
|
||||
|
||||
$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
|
||||
|
||||
ifdef NO_SPLICING
|
||||
override CFLAGS += -DNO_SPLICING
|
||||
endif
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
$(info Compiling ASAN version of binaries)
|
||||
override CFLAGS += $(ASAN_CFLAGS)
|
||||
LDFLAGS += $(ASAN_LDFLAGS)
|
||||
endif
|
||||
ifdef UBSAN_BUILD
|
||||
$(info Compiling UBSAN version of binaries)
|
||||
override CFLAGS += -fsanitize=undefined -fno-omit-frame-pointer
|
||||
override LDFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
ifdef MSAN_BUILD
|
||||
$(info Compiling MSAN version of binaries)
|
||||
CC := clang
|
||||
override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
|
||||
override LDFLAGS += -fsanitize=memory
|
||||
endif
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
|
||||
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 "$(SYS)" "Darwin"
|
||||
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
ifndef DEBUG
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
CFLAGS_OPT += -Wno-format-truncation
|
||||
LDFLAGS = -lkstat -lrt
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries, disabling python though)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK = 0
|
||||
PYFLAGS=
|
||||
PYTHON_INCLUDE = /
|
||||
|
||||
CFLAGS_OPT += -static
|
||||
LDFLAGS += -lm -lpthread -lz -lutil
|
||||
endif
|
||||
|
||||
ifdef PROFILING
|
||||
$(info Compiling with profiling information, for analysis: gprof ./afl-fuzz gmon.out > prof.txt)
|
||||
CFLAGS_OPT += -pg -DPROFILING=1
|
||||
LDFLAGS += -pg
|
||||
endif
|
||||
|
||||
ifdef INTROSPECTION
|
||||
$(info Compiling with introspection documentation)
|
||||
CFLAGS_OPT += -DINTROSPECTION=1
|
||||
endif
|
||||
|
||||
ifneq "$(ARCH)" "x86_64"
|
||||
ifneq "$(patsubst i%86,i386,$(ARCH))" "i386"
|
||||
ifneq "$(ARCH)" "amd64"
|
||||
ifneq "$(ARCH)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
$(info Compiling DEBUG version of binaries)
|
||||
CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror
|
||||
else
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
endif
|
||||
|
||||
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
|
||||
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
|
||||
ifeq "$(SYS)" "FreeBSD"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
LDFLAGS += -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "DragonFly"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
LDFLAGS += -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
override CFLAGS += -I /usr/local/include/ -mno-retpoline
|
||||
LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "NetBSD"
|
||||
override CFLAGS += -I /usr/pkg/include/
|
||||
LDFLAGS += -L /usr/pkg/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "Haiku"
|
||||
SHMAT_OK=0
|
||||
override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC
|
||||
LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
|
||||
SPECIAL_PERFORMANCE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
ifneq "$(shell command -v python3m 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
|
||||
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3m-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python3 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python-config --includes)
|
||||
PYTHON_LIB ?= $(shell python-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Old Ubuntu and others dont have python/python3-config so we hardcode 3.7
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python3.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
|
||||
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
|
||||
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
else
|
||||
BUILD_DATE ?= $(shell date "+%Y-%m-%d")
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(SYS))" ""
|
||||
ifndef DEBUG
|
||||
override CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
LDFLAGS += -ldl -lrt -lm
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring OpenBSD, $(SYS))" ""
|
||||
override CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef NO_PYTHON
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
IN_REPO=0
|
||||
ifeq "$(shell command -v git >/dev/null && git status >/dev/null 2>&1 && echo 1 || echo 0)" "1"
|
||||
IN_REPO=1
|
||||
endif
|
||||
ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1 || echo 0)" "1"
|
||||
IN_REPO=1
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
override CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifdef TEST_MMAP
|
||||
SHMAT_OK=0
|
||||
override CFLAGS += -DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done
|
||||
|
||||
.PHONY: llvm
|
||||
llvm:
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
gcc_plugin:
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
|
||||
.PHONY: man
|
||||
man: $(MANPAGES)
|
||||
|
||||
.PHONY: test
|
||||
test: tests
|
||||
|
||||
.PHONY: tests
|
||||
tests: source-only
|
||||
@cd test ; ./test-all.sh
|
||||
@rm -f test/errors
|
||||
|
||||
.PHONY: performance-tests
|
||||
performance-tests: performance-test
|
||||
.PHONY: test-performance
|
||||
test-performance: performance-test
|
||||
|
||||
.PHONY: performance-test
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
# hint: make targets are also listed in the top level README.md
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
|
||||
@echo "source-only: everything for source code fuzzing: gcc_plugin, libdislocator, libtokencap"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything compiled (not downloads when on a checkout)"
|
||||
@echo "deepclean: cleans everything including downloads"
|
||||
@echo "code-format: format the code, do this before you commit and send a PR please!"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "unit: perform unit tests (based on cmocka and GNU linker)"
|
||||
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
|
||||
@echo "help: shows these build options :-)"
|
||||
@echo "=========================================="
|
||||
@echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
|
||||
@echo
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
.PHONY: test_x86
|
||||
ifndef AFL_NO_X86
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@echo "[*] Testing the PATH environment variable..."
|
||||
@test "$${PATH}" != "$${PATH#.:}" && { echo "Please remove current directory '.' from PATH to avoid recursion of 'as', thanks!"; echo; exit 1; } || :
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
else
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
endif
|
||||
|
||||
.PHONY: test_shm
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
else
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
endif
|
||||
|
||||
.PHONY: test_python
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
else
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
endif
|
||||
|
||||
.PHONY: ready
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
@ln -sf afl-as as
|
||||
|
||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
||||
$(CC) $(CFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
|
||||
.PHONY: document
|
||||
document: afl-fuzz-document
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
|
||||
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
|
||||
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_maybe_alloc
|
||||
|
||||
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
|
||||
|
||||
unit_hash: test/unittests/unit_hash.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_hash
|
||||
|
||||
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
|
||||
|
||||
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_rand
|
||||
|
||||
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
|
||||
unit_list: test/unittests/unit_list.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_list
|
||||
|
||||
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
|
||||
unit_preallocable: test/unittests/unit_preallocable.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_preallocable
|
||||
|
||||
.PHONY: unit_clean
|
||||
unit_clean:
|
||||
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
|
||||
|
||||
.PHONY: unit
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
|
||||
else
|
||||
unit:
|
||||
@echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
|
||||
endif
|
||||
|
||||
.PHONY: code-format
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i instrumentation/*.h
|
||||
./.custom-format.py -i instrumentation/*.cc
|
||||
./.custom-format.py -i instrumentation/*.c
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
@#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
|
||||
@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
|
||||
./.custom-format.py -i utils/*/*.c*
|
||||
./.custom-format.py -i utils/*/*.h
|
||||
./.custom-format.py -i test/*.c
|
||||
./.custom-format.py -i frida_mode/src/*.c
|
||||
./.custom-format.py -i frida_mode/include/*.h
|
||||
-./.custom-format.py -i frida_mode/src/*/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qemu_mode/libqasan/*.c
|
||||
./.custom-format.py -i qemu_mode/libqasan/*.h
|
||||
|
||||
|
||||
.PHONY: test_build
|
||||
ifndef AFL_NO_X86
|
||||
test_build: afl-cc afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
|
||||
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo
|
||||
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
|
||||
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
|
||||
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
|
||||
# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
# @rm -f test-instr
|
||||
# @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-gcc does not seem to be behaving correctly!"; \
|
||||
# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option."; echo "See docs/INSTALL.md section 5 how to build a -B enabled gcc." ) || \
|
||||
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
|
||||
# @echo
|
||||
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
|
||||
else
|
||||
test_build: afl-cc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
endif
|
||||
|
||||
.PHONY: all_done
|
||||
all_done: test_build
|
||||
@test -e afl-cc && echo "[+] Main compiler 'afl-cc' successfully built!" || { echo "[-] Main compiler 'afl-cc' failed to build, set up a working build environment first!" ; exit 1 ; }
|
||||
@test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!"
|
||||
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
|
||||
@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean all
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand
|
||||
-$(MAKE) -f GNUmakefile.llvm clean
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin clean
|
||||
$(MAKE) -C utils/libdislocator clean
|
||||
$(MAKE) -C utils/libtokencap clean
|
||||
$(MAKE) -C utils/aflpp_driver clean
|
||||
$(MAKE) -C utils/afl_network_proxy clean
|
||||
$(MAKE) -C utils/socket_fuzzing clean
|
||||
$(MAKE) -C utils/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C qemu_mode/libqasan clean
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
|
||||
test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
else
|
||||
rm -rf qemu_mode/qemuafl
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
endif
|
||||
|
||||
.PHONY: deepclean
|
||||
deepclean: clean
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
rm -rf qemu_mode/qemuafl
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
|
||||
git checkout unicorn_mode/unicornafl
|
||||
git checkout qemu_mode/qemuafl
|
||||
endif
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
-$(MAKE) -C utils/aflpp_driver
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-$(MAKE) -C frida_mode
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
.PHONY: binary-only
|
||||
binary-only: test_shm test_python ready $(PROGS)
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
$(MAKE) -C utils/afl_network_proxy
|
||||
$(MAKE) -C utils/socket_fuzzing
|
||||
$(MAKE) -C utils/argv_fuzzing
|
||||
-$(MAKE) -C frida_mode
|
||||
-cd qemu_mode && sh ./build_qemu_support.sh
|
||||
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
|
||||
|
||||
.PHONY: source-only
|
||||
source-only: all
|
||||
-$(MAKE) -j -f GNUmakefile.llvm
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin
|
||||
$(MAKE) -C utils/libdislocator
|
||||
$(MAKE) -C utils/libtokencap
|
||||
-$(MAKE) -C utils/aflpp_driver
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -hh 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
.PHONY: install
|
||||
install: all $(MANPAGES)
|
||||
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
@rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f libqasan.so ]; then set -e; install -m 755 libqasan.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
|
||||
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
|
||||
@if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
|
||||
@if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
|
||||
-$(MAKE) -f GNUmakefile.llvm install
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin install
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
|
||||
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
187
GNUmakefile.gcc_plugin
Normal file
187
GNUmakefile.gcc_plugin
Normal file
@ -0,0 +1,187 @@
|
||||
#
|
||||
# american fuzzy lop++ - GCC plugin instrumentation
|
||||
# -----------------------------------------------
|
||||
#
|
||||
# Written by Austin Seipp <aseipp@pobox.com> and
|
||||
# Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski and
|
||||
# Heiko Eißfeldt <heiko@hexco.de>
|
||||
#
|
||||
# GCC integration design is based on the LLVM design, which comes
|
||||
# from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
#TEST_MMAP=1
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
override CFLAGS += $(CFLAGS_SAFE)
|
||||
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
ifeq "clang" "$(CC)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
ifeq "clang++" "$(CXX)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
ifeq "$(findstring Foundation,$(shell $(CC) --version))" ""
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
PLUGIN_BASE = "$(shell $(CC) -print-file-name=plugin)"
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE)
|
||||
HASH=\#
|
||||
|
||||
GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCBINDIR = $(shell dirname `command -v $(CC)` 2>/dev/null )
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
override CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
override CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifneq "$(SYS)" "Haiku"
|
||||
ifneq "$(SYS)" "OpenBSD"
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
else
|
||||
CFLAGS_SAFE += -DUSEMMAP=1
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CC = egcc
|
||||
CXX = eg++
|
||||
PLUGIN_FLAGS += -I/usr/local/include
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "DragonFly"
|
||||
PLUGIN_FLAGS += -I/usr/local/include
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "SunOS"
|
||||
PLUGIN_FLAGS += -I/usr/include/gmp
|
||||
endif
|
||||
|
||||
|
||||
PROGS = ./afl-gcc-pass.so
|
||||
|
||||
.PHONY: all
|
||||
all: test_shm test_deps $(PROGS) test_build all_done
|
||||
|
||||
.PHONY: test_shm
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
else
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
endif
|
||||
|
||||
.PHONY: test_deps
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@command -v $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for './afl-showmap'..."
|
||||
@test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ./src/afl-common.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
ln -sf afl-cc afl-gcc-fast
|
||||
ln -sf afl-cc afl-g++-fast
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
ln -sf afl-cc.8 afl-g++-fast.8
|
||||
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
.PHONY: all_done
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use './afl-gcc-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
|
||||
@echo .SH NAME >> ./$@
|
||||
@echo .B $* >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH SYNOPSIS >> ./$@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH OPTIONS >> ./$@
|
||||
@echo .nf >> ./$@
|
||||
@./$* -h 2>&1 | tail -n +4 >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH AUTHOR >> ./$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
ln -sf afl-cc.8 ./afl-g++-fast.8
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast
|
||||
ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast
|
||||
ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
|
||||
install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ./afl-g++-fast ./afl-g*-fast.8 instrumentation/*.o
|
523
GNUmakefile.llvm
Normal file
523
GNUmakefile.llvm
Normal file
@ -0,0 +1,523 @@
|
||||
# american fuzzy lop++ - LLVM instrumentation
|
||||
# -----------------------------------------
|
||||
#
|
||||
# Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# LLVM integration design comes from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MISC_PATH ?= $(PREFIX)/share/afl
|
||||
MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
ifeq "$(HAS_OPT)" "1"
|
||||
$(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
|
||||
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 )
|
||||
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
|
||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||
LLVM_STDCXX = gnu++11
|
||||
LLVM_APPLE_XCODE = $(shell clang -v 2>&1 | grep -q Apple && echo 1 || echo 0)
|
||||
LLVM_LTO = 0
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning [!] llvm_mode needs llvm-config, which was not found)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(error llvm_mode only supports llvm from version 6.0 onwards)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_NEW)" "1"
|
||||
$(warning you are using an in-development llvm version - this might break llvm_mode!)
|
||||
endif
|
||||
|
||||
LLVM_TOO_OLD=1
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
LLVM_TOO_OLD=0
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
LLVM_STDCXX = c++14
|
||||
LLVM_TOO_OLD=0
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_OLD)" "1"
|
||||
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
|
||||
$(shell sleep 1)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_HAVE_LTO)" "1"
|
||||
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
#TEST_MMAP = 1
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "0"
|
||||
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE_XCODE)" "1"
|
||||
$(warning llvm_mode will not compile with Xcode clang...)
|
||||
endif
|
||||
|
||||
# We were using llvm-config --bindir to get the location of clang, but
|
||||
# this seems to be busted on some distros, so using the one in $PATH is
|
||||
# probably better.
|
||||
|
||||
CC = $(LLVM_BINDIR)/clang
|
||||
CXX = $(LLVM_BINDIR)/clang++
|
||||
|
||||
# llvm-config --bindir may not providing a valid path, so ...
|
||||
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
|
||||
# however we must ensure that this is not a "CC=gcc make"
|
||||
ifeq "$(shell command -v $(CC) 2> /dev/null)" ""
|
||||
# we do not have a valid CC variable so we try alternatives
|
||||
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
|
||||
# we found one in the local install directory, lets use these
|
||||
CC = $(BIN_DIR)/clang
|
||||
else
|
||||
# hope for the best
|
||||
$(warning we have trouble finding clang - llvm-config is not helping us)
|
||||
CC = clang
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
# llvm-config --bindir may not providing a valid path, so ...
|
||||
ifeq "$(shell test -e $(CXX) || echo 1 )" "1"
|
||||
# however we must ensure that this is not a "CXX=g++ make"
|
||||
ifeq "$(shell command -v $(CXX) 2> /dev/null)" ""
|
||||
# we do not have a valid CXX variable so we try alternatives
|
||||
ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1"
|
||||
# we found one in the local install directory, lets use these
|
||||
CXX = $(BIN_DIR)/clang++
|
||||
else
|
||||
# hope for the best
|
||||
$(warning we have trouble finding clang++ - llvm-config is not helping us)
|
||||
CXX = clang++
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# sanity check.
|
||||
# Are versions of clang --version and llvm-config --version equal?
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
|
||||
# I disable this because it does not make sense with what we did before (marc)
|
||||
# We did exactly set these 26 lines above with these values, and it would break
|
||||
# "CC=gcc make" etc. usages
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
CC_SAVE := $(LLVM_BINDIR)/clang
|
||||
else
|
||||
CC_SAVE := $(CC)
|
||||
endif
|
||||
ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" ""
|
||||
CXX_SAVE := $(LLVM_BINDIR)/clang++
|
||||
else
|
||||
CXX_SAVE := $(CXX)
|
||||
endif
|
||||
|
||||
CLANG_BIN := $(CC_SAVE)
|
||||
CLANGPP_BIN := $(CXX_SAVE)
|
||||
|
||||
ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang"
|
||||
USE_BINDIR = 1
|
||||
else
|
||||
ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++"
|
||||
USE_BINDIR = 1
|
||||
else
|
||||
USE_BINDIR = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
# On old platform we cannot compile with clang because std++ libraries are too
|
||||
# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX
|
||||
# variable we override the compiler variables here
|
||||
ifneq "$(REAL_CC)" ""
|
||||
CC = $(REAL_CC)
|
||||
endif
|
||||
ifneq "$(REAL_CXX)" ""
|
||||
CXX = $(REAL_CXX)
|
||||
endif
|
||||
|
||||
#
|
||||
# Now it can happen that CC points to clang - but there is no clang on the
|
||||
# system. Then we fall back to cc
|
||||
#
|
||||
ifeq "$(shell command -v $(CC) 2>/dev/null)" ""
|
||||
CC = cc
|
||||
endif
|
||||
ifeq "$(shell command -v $(CXX) 2>/dev/null)" ""
|
||||
CXX = c++
|
||||
endif
|
||||
|
||||
|
||||
# After we set CC/CXX we can start makefile magic tests
|
||||
|
||||
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
# CFLAGS_OPT = -march=native
|
||||
#endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(AFL_REAL_LD)" ""
|
||||
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
||||
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
||||
else
|
||||
$(warning ld.lld not found, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
else
|
||||
$(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
AFL_CLANG_FUSELD=
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_FUSELD=1
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_LDPATH=1
|
||||
endif
|
||||
else
|
||||
$(warning -fuse-ld is not working, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
|
||||
else
|
||||
AFL_CLANG_DEBUG_PREFIX =
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
|
||||
CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
|
||||
-Wno-deprecated -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
|
||||
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
|
||||
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \
|
||||
-DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
|
||||
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function \
|
||||
$(AFL_CLANG_DEBUG_PREFIX)
|
||||
override CFLAGS += $(CFLAGS_SAFE)
|
||||
|
||||
ifdef AFL_TRACE_PC
|
||||
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
|
||||
override CXXFLAGS += -Wall -g -I ./include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros \
|
||||
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
|
||||
|
||||
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
|
||||
CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir)
|
||||
endif
|
||||
ifneq "$(LLVM_CONFIG)" ""
|
||||
CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
|
||||
endif
|
||||
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(SYS)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
else
|
||||
CLANG_CPPFL += -Wl,-znodelete
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
CLANG_CPPFL += -mno-retpoline
|
||||
CFLAGS += -mno-retpoline
|
||||
# Needed for unwind symbols
|
||||
LDFLAGS += -lc++abi -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS_SAFE += -DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS_SAFE += -DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = test_shm $(PROGS_ALWAYS) afl-cc.8
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-cc.8 test_build all_done
|
||||
endif
|
||||
|
||||
LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: test_shm
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
else
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
endif
|
||||
|
||||
.PHONY: no_build
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
.PHONY: test_deps
|
||||
test_deps:
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE_XCODE)" "1"
|
||||
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 )
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
|
||||
else
|
||||
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
|
||||
endif
|
||||
@echo "[*] Checking for './afl-showmap'..."
|
||||
@test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
instrumentation/afl-common.o: ./src/afl-common.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
./afl-cc: src/afl-cc.c instrumentation/afl-common.o
|
||||
$(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -lm
|
||||
@ln -sf afl-cc ./afl-c++
|
||||
@ln -sf afl-cc ./afl-gcc
|
||||
@ln -sf afl-cc ./afl-g++
|
||||
@ln -sf afl-cc ./afl-clang
|
||||
@ln -sf afl-cc ./afl-clang++
|
||||
@ln -sf afl-cc ./afl-clang-fast
|
||||
@ln -sf afl-cc ./afl-clang-fast++
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
@ln -sf afl-cc ./afl-clang-lto
|
||||
@ln -sf afl-cc ./afl-clang-lto++
|
||||
@ln -sf afl-cc ./afl-lto
|
||||
@ln -sf afl-cc ./afl-lto++
|
||||
endif
|
||||
endif
|
||||
|
||||
instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
|
||||
|
||||
./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_MIN_4_0_1)" "0"
|
||||
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
|
||||
endif
|
||||
$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_10_OK)" "1"
|
||||
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
endif
|
||||
|
||||
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
endif
|
||||
|
||||
./afl-ld-lto: src/afl-ld-lto.c
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
endif
|
||||
|
||||
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
endif
|
||||
|
||||
./afl-llvm-lto-instrumentation.so: instrumentation/afl-llvm-lto-instrumentation.so.cc instrumentation/afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
|
||||
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
endif
|
||||
|
||||
# laf
|
||||
./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
# /laf
|
||||
|
||||
./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
.PHONY: document
|
||||
document:
|
||||
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt.o
|
||||
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
|
||||
$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
|
||||
|
||||
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
|
||||
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
.PHONY: all_done
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use './afl-cc' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
|
||||
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o ;fi
|
||||
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o ;fi
|
||||
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o ; fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
|
||||
@if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
|
||||
set -e; install -m 644 ./dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@
|
||||
@echo .SH NAME >> ./$@
|
||||
@printf "%s" ".B $* \- " >> ./$@
|
||||
@./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@
|
||||
@echo .B $* >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH SYNOPSIS >> ./$@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH OPTIONS >> ./$@
|
||||
@echo .nf >> ./$@
|
||||
@./$* -h 2>&1 | tail -n +4 >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH AUTHOR >> ./$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
|
||||
@echo >> ./$@
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
@ln -sf afl-cc.8 ./afl-c++.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast++.8
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
@ln -sf afl-cc.8 ./afl-clang-lto.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-lto++.8
|
||||
@ln -sf afl-cc.8 ./afl-lto.8
|
||||
@ln -sf afl-cc.8 ./afl-lto++.8
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
|
||||
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-llvm-rt*.o instrumentation/*.o
|
171
Makefile
171
Makefile
@ -1,157 +1,42 @@
|
||||
#
|
||||
# american fuzzy lop - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
#
|
||||
# Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
all:
|
||||
@echo trying to use GNU make...
|
||||
@gmake all || echo please install GNUmake
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^\#define VERSION ' config.h | cut -d '"' -f2)
|
||||
source-only:
|
||||
@gmake source-only
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
binary-only:
|
||||
@gmake binary-only
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
distrib:
|
||||
@gmake distrib
|
||||
|
||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-whatsup afl-system-config
|
||||
man:
|
||||
@gmake man
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\"
|
||||
install:
|
||||
@gmake install
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
document:
|
||||
@gmake document
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
deepclean:
|
||||
@gmake deepclean
|
||||
|
||||
COMM_HDR = alloc-inl.h config.h debug.h types.h
|
||||
code-format:
|
||||
@gmake code-format
|
||||
|
||||
all: test_x86 $(PROGS) afl-as test_build all_done
|
||||
help:
|
||||
@gmake help
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
tests:
|
||||
@gmake tests
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
unit:
|
||||
@gmake unit
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
afl-gcc: afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: afl-as.c afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
afl-fuzz: afl-fuzz.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
|
||||
afl-showmap: afl-showmap.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: afl-tmin.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: afl-analyze.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS)
|
||||
echo 0 | ./afl-showmap -m none -q -o .test-instr0 ./test-instr
|
||||
echo 1 | ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please ping <lcamtuf@google.com> to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
all_done: test_build
|
||||
@if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review README - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.txt for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
unit_clean:
|
||||
@gmake unit_clean
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.10.0.tar.bz2 afl-qemu-trace
|
||||
rm -rf out_dir qemu_mode/qemu-2.10.0
|
||||
$(MAKE) -C llvm_mode clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
|
||||
install: all
|
||||
mkdir -p -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
ifndef AFL_TRACE_PC
|
||||
if [ -f afl-clang-fast -a -f afl-llvm-pass.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
else
|
||||
if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
endif
|
||||
if [ -f afl-llvm-rt-32.o ]; then set -e; install -m 755 afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-llvm-rt-64.o ]; then set -e; install -m 755 afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f compare-transform-pass.so ]; then set -e; install -m 755 compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-compares-pass.so ]; then set -e; install -m 755 split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-switches-pass.so ]; then set -e; install -m 755 split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/$$i; done
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/README docs/ChangeLog docs/*.txt $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
||||
|
||||
publish: clean
|
||||
test "`basename $$PWD`" = "afl" || exit 1
|
||||
test -f ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz; if [ "$$?" = "0" ]; then echo; echo "Change program version in config.h, mmkay?"; echo; exit 1; fi
|
||||
cd ..; rm -rf $(PROGNAME)-$(VERSION); cp -pr $(PROGNAME) $(PROGNAME)-$(VERSION); \
|
||||
tar -cvz -f ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz $(PROGNAME)-$(VERSION)
|
||||
chmod 644 ~/www/afl/releases/$(PROGNAME)-$(VERSION).tgz
|
||||
( cd ~/www/afl/releases/; ln -s -f $(PROGNAME)-$(VERSION).tgz $(PROGNAME)-latest.tgz )
|
||||
cat docs/README >~/www/afl/README.txt
|
||||
cat docs/status_screen.txt >~/www/afl/status_screen.txt
|
||||
cat docs/historical_notes.txt >~/www/afl/historical_notes.txt
|
||||
cat docs/technical_details.txt >~/www/afl/technical_details.txt
|
||||
cat docs/ChangeLog >~/www/afl/ChangeLog.txt
|
||||
cat docs/QuickStartGuide.txt >~/www/afl/QuickStartGuide.txt
|
||||
echo -n "$(VERSION)" >~/www/afl/version.txt
|
||||
@gmake clean
|
||||
|
1
QuickStartGuide.md
Symbolic link
1
QuickStartGuide.md
Symbolic link
@ -0,0 +1 @@
|
||||
docs/QuickStartGuide.md
|
@ -1 +0,0 @@
|
||||
docs/QuickStartGuide.txt
|
40
TODO.md
Normal file
40
TODO.md
Normal file
@ -0,0 +1,40 @@
|
||||
# TODO list for AFL++
|
||||
|
||||
## Roadmap 3.00+
|
||||
|
||||
- align map to 64 bytes but keep real IDs
|
||||
- Update afl->pending_not_fuzzed for MOpt
|
||||
- put fuzz target in top line of UI
|
||||
- afl-plot to support multiple plot_data
|
||||
- afl_custom_fuzz_splice_optin()
|
||||
- afl_custom_splice()
|
||||
- intel-pt tracer
|
||||
- better autodetection of shifting runtime timeout values
|
||||
- cmplog: use colorization input for havoc?
|
||||
- parallel builds for source-only targets
|
||||
|
||||
|
||||
## Further down the road
|
||||
|
||||
afl-fuzz:
|
||||
- setting min_len/max_len/start_offset/end_offset limits for mutation output
|
||||
|
||||
qemu_mode:
|
||||
- non colliding instrumentation
|
||||
- rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END,
|
||||
AFL_COMPCOV_LEVEL?)
|
||||
- add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as we have
|
||||
persistent mode
|
||||
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
|
||||
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses
|
||||
|
||||
|
||||
## Ideas
|
||||
|
||||
- LTO/sancov: write current edge to prev_loc and use that information when
|
||||
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow
|
||||
up edge numbers that both following cmp paths have been found and then
|
||||
disable working on this edge id -> cmplog_intelligence branch
|
||||
- use cmplog colorization taint result for havoc locations?
|
||||
- new instrumentation option for a thread-safe variant of feedback to shared mem.
|
||||
The user decides, if this is needed (eg the target is multithreaded).
|
1073
afl-analyze.c
1073
afl-analyze.c
File diff suppressed because it is too large
Load Diff
916
afl-cmin
916
afl-cmin
@ -1,461 +1,535 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
export AFL_QUIET=1
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
THISPATH=`dirname ${0}`
|
||||
export PATH="${THISPATH}:$PATH"
|
||||
awk -f - -- ${@+"$@"} <<'EOF'
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
# awk script to minimize a test corpus of input files
|
||||
#
|
||||
# american fuzzy lop - corpus minimization tool
|
||||
# ---------------------------------------------
|
||||
# based on afl-cmin bash script written by Michal Zalewski
|
||||
# rewritten by Heiko Eißfeldt (hexcoder-)
|
||||
# tested with:
|
||||
# gnu awk (x86 Linux)
|
||||
# bsd awk (x86 *BSD)
|
||||
# mawk (arm32 raspbian)
|
||||
#
|
||||
# Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
#
|
||||
# Copyright 2014, 2015 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# This tool tries to find the smallest subset of files in the input directory
|
||||
# that still trigger the full range of instrumentation data points seen in
|
||||
# the starting corpus. This has two uses:
|
||||
#
|
||||
# - Screening large corpora of input files before using them as a seed for
|
||||
# afl-fuzz. The tool will remove functionally redundant files and likely
|
||||
# leave you with a much smaller set.
|
||||
#
|
||||
# (In this case, you probably also want to consider running afl-tmin on
|
||||
# the individual files later on to reduce their size.)
|
||||
#
|
||||
# - Minimizing the corpus generated organically by afl-fuzz, perhaps when
|
||||
# planning to feed it to more resource-intensive tools. The tool achieves
|
||||
# this by removing all entries that used to trigger unique behaviors in the
|
||||
# past, but have been made obsolete by later finds.
|
||||
#
|
||||
# Note that the tool doesn't modify the files themselves. For that, you want
|
||||
# afl-tmin.
|
||||
#
|
||||
# This script must use bash because other shells may have hardcoded limits on
|
||||
# array sizes.
|
||||
# uses getopt.awk package from Arnold Robbins
|
||||
#
|
||||
# external tools used by this script:
|
||||
# test
|
||||
# grep
|
||||
# rm
|
||||
# mkdir
|
||||
# ln
|
||||
# cp
|
||||
# pwd
|
||||
# type
|
||||
# cd
|
||||
# find
|
||||
# stat
|
||||
# sort
|
||||
# cut
|
||||
# and afl-showmap from this project :-)
|
||||
|
||||
echo "corpus minimization tool for afl-fuzz by <lcamtuf@google.com>"
|
||||
echo
|
||||
# getopt.awk --- Do C library getopt(3) function in awk
|
||||
|
||||
#########
|
||||
# SETUP #
|
||||
#########
|
||||
# External variables:
|
||||
# Optind -- index in ARGV of first nonoption argument
|
||||
# Optarg -- string value of argument to current option
|
||||
# Opterr -- if nonzero, print our own diagnostic
|
||||
# Optopt -- current option letter
|
||||
|
||||
# Process command-line options...
|
||||
# Returns:
|
||||
# -1 at end of options
|
||||
# "?" for unrecognized option
|
||||
# <c> a character representing the current option
|
||||
|
||||
MEM_LIMIT=100
|
||||
TIMEOUT=none
|
||||
# Private Data:
|
||||
# _opti -- index in multiflag option, e.g., -abc
|
||||
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE
|
||||
function getopt(argc, argv, options, thisopt, i)
|
||||
{
|
||||
if (length(options) == 0) # no options given
|
||||
return -1
|
||||
|
||||
while getopts "+i:o:f:m:t:eQC" opt; do
|
||||
if (argv[Optind] == "--") { # all done
|
||||
Optind++
|
||||
_opti = 0
|
||||
return -1
|
||||
} else if (argv[Optind] !~ /^-[^:\t ]/) {
|
||||
_opti = 0
|
||||
return -1
|
||||
}
|
||||
if (_opti == 0)
|
||||
_opti = 2
|
||||
thisopt = substr(argv[Optind], _opti, 1)
|
||||
Optopt = thisopt
|
||||
i = index(options, thisopt)
|
||||
if (i == 0) {
|
||||
if (Opterr)
|
||||
printf("%c -- invalid option\n", thisopt) > "/dev/stderr"
|
||||
if (_opti >= length(argv[Optind])) {
|
||||
Optind++
|
||||
_opti = 0
|
||||
} else
|
||||
_opti++
|
||||
return "?"
|
||||
}
|
||||
if (substr(options, i + 1, 1) == ":") {
|
||||
# get option argument
|
||||
if (length(substr(argv[Optind], _opti + 1)) > 0)
|
||||
Optarg = substr(argv[Optind], _opti + 1)
|
||||
else
|
||||
Optarg = argv[++Optind]
|
||||
_opti = 0
|
||||
} else
|
||||
Optarg = ""
|
||||
if (_opti == 0 || _opti >= length(argv[Optind])) {
|
||||
Optind++
|
||||
_opti = 0
|
||||
} else
|
||||
_opti++
|
||||
return thisopt
|
||||
}
|
||||
|
||||
case "$opt" in
|
||||
function usage() {
|
||||
print \
|
||||
"afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
|
||||
"\n" \
|
||||
"Required parameters:\n" \
|
||||
" -i dir - input directory with starting corpus\n" \
|
||||
" -o dir - output directory for minimized files\n" \
|
||||
"\n" \
|
||||
"Execution control settings:\n" \
|
||||
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||
" -t msec - run time limit for child process (none)\n" \
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n" \
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n" \
|
||||
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
|
||||
"\n" \
|
||||
"Minimization settings:\n" \
|
||||
" -C - keep crashing inputs, reject everything else\n" \
|
||||
" -e - solve for edge coverage only, ignore hit counts\n" \
|
||||
"\n" \
|
||||
"For additional tips, please consult README.md\n" \
|
||||
"\n" \
|
||||
"Environment variables used:\n" \
|
||||
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
|
||||
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
|
||||
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
|
||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||
"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
|
||||
"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
|
||||
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
|
||||
"printed to stdout\n" \
|
||||
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
"i")
|
||||
IN_DIR="$OPTARG"
|
||||
;;
|
||||
function exists_and_is_executable(binarypath) {
|
||||
return 0 == system("test -f "binarypath" -a -x "binarypath)
|
||||
}
|
||||
|
||||
"o")
|
||||
OUT_DIR="$OPTARG"
|
||||
;;
|
||||
"f")
|
||||
STDIN_FILE="$OPTARG"
|
||||
;;
|
||||
"m")
|
||||
MEM_LIMIT="$OPTARG"
|
||||
MEM_LIMIT_GIVEN=1
|
||||
;;
|
||||
"t")
|
||||
TIMEOUT="$OPTARG"
|
||||
;;
|
||||
"e")
|
||||
EXTRA_PAR="$EXTRA_PAR -e"
|
||||
;;
|
||||
"C")
|
||||
export AFL_CMIN_CRASHES_ONLY=1
|
||||
;;
|
||||
"Q")
|
||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||
QEMU_MODE=1
|
||||
;;
|
||||
"?")
|
||||
exit 1
|
||||
;;
|
||||
BEGIN {
|
||||
print "corpus minimization tool for afl++ (awk version)\n"
|
||||
|
||||
esac
|
||||
# defaults
|
||||
extra_par = ""
|
||||
AFL_CMIN_CRASHES_ONLY = ""
|
||||
|
||||
done
|
||||
# process options
|
||||
Opterr = 1 # default is to diagnose
|
||||
Optind = 1 # skip ARGV[0]
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
|
||||
if (_go_c == "i") {
|
||||
if (!Optarg) usage()
|
||||
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
in_dir = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "o") {
|
||||
if (!Optarg) usage()
|
||||
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
out_dir = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "f") {
|
||||
if (!Optarg) usage()
|
||||
if (stdin_file) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
stdin_file = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "m") {
|
||||
if (!Optarg) usage()
|
||||
if (mem_limit) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
mem_limit = Optarg
|
||||
mem_limit_given = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "t") {
|
||||
if (!Optarg) usage()
|
||||
if (timeout) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
timeout = Optarg
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "C") {
|
||||
AFL_CMIN_CRASHES_ONLY = "AFL_CMIN_CRASHES_ONLY=1 "
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "e") {
|
||||
extra_par = extra_par " -e"
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "O") {
|
||||
if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -O"
|
||||
frida_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "Q") {
|
||||
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -Q"
|
||||
qemu_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "U") {
|
||||
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -U"
|
||||
unicorn_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "?") {
|
||||
exit 1
|
||||
} else
|
||||
usage()
|
||||
} # while options
|
||||
|
||||
shift $((OPTIND-1))
|
||||
if (!mem_limit) mem_limit = "none"
|
||||
if (!timeout) timeout = "none"
|
||||
|
||||
TARGET_BIN="$1"
|
||||
# get program args
|
||||
i = 0
|
||||
prog_args_string = ""
|
||||
for (; Optind < ARGC; Optind++) {
|
||||
prog_args[i++] = ARGV[Optind]
|
||||
if (i > 1)
|
||||
prog_args_string = prog_args_string" "ARGV[Optind]
|
||||
}
|
||||
|
||||
if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
|
||||
# sanity checks
|
||||
if (!prog_args[0] || !in_dir || !out_dir) usage()
|
||||
|
||||
cat 1>&2 <<_EOF_
|
||||
Usage: $0 [ options ] -- /path/to/target_app [ ... ]
|
||||
target_bin = prog_args[0]
|
||||
|
||||
Required parameters:
|
||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||
# handle this safely from an awk script.
|
||||
|
||||
-i dir - input directory with the starting corpus
|
||||
-o dir - output directory for minimized files
|
||||
if (!ENVIRON["AFL_ALLOW_TMP"]) {
|
||||
dirlist[0] = in_dir
|
||||
dirlist[1] = target_bin
|
||||
dirlist[2] = out_dir
|
||||
dirlist[3] = stdin_file
|
||||
"pwd" | getline dirlist[4] # current directory
|
||||
for (dirind in dirlist) {
|
||||
dir = dirlist[dirind]
|
||||
|
||||
Execution control settings:
|
||||
if (dir ~ /^(\/var)?\/tmp/) {
|
||||
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
delete dirlist
|
||||
}
|
||||
|
||||
-f file - location read by the fuzzed program (stdin)
|
||||
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
||||
-t msec - run time limit for child process (none)
|
||||
-Q - use binary-only instrumentation (QEMU mode)
|
||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||
# file name.
|
||||
|
||||
Minimization settings:
|
||||
trace_dir = out_dir "/.traces"
|
||||
|
||||
-C - keep crashing inputs, reject everything else
|
||||
-e - solve for edge coverage only, ignore hit counts
|
||||
if (!stdin_file) {
|
||||
found_atat = 0
|
||||
for (prog_args_ind in prog_args) {
|
||||
if (match(prog_args[prog_args_ind], "@@") != 0) {
|
||||
found_atat = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if (found_atat) {
|
||||
stdin_file = trace_dir "/.cur_input"
|
||||
}
|
||||
}
|
||||
|
||||
For additional tips, please consult docs/README.
|
||||
# Check for obvious errors.
|
||||
|
||||
_EOF_
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||
# handle this safely from a shell script.
|
||||
|
||||
if [ "$AFL_ALLOW_TMP" = "" ]; then
|
||||
|
||||
echo "$IN_DIR" | grep -qE '^(/var)?/tmp/'
|
||||
T1="$?"
|
||||
|
||||
echo "$TARGET_BIN" | grep -qE '^(/var)?/tmp/'
|
||||
T2="$?"
|
||||
|
||||
echo "$OUT_DIR" | grep -qE '^(/var)?/tmp/'
|
||||
T3="$?"
|
||||
|
||||
echo "$STDIN_FILE" | grep -qE '^(/var)?/tmp/'
|
||||
T4="$?"
|
||||
|
||||
echo "$PWD" | grep -qE '^(/var)?/tmp/'
|
||||
T5="$?"
|
||||
|
||||
if [ "$T1" = "0" -o "$T2" = "0" -o "$T3" = "0" -o "$T4" = "0" -o "$T5" = "0" ]; then
|
||||
echo "[-] Error: do not use this script in /tmp or /var/tmp." 1>&2
|
||||
if (mem_limit && mem_limit != "none" && mem_limit < 5) {
|
||||
print "[-] Error: dangerously low memory limit." > "/dev/stderr"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fi
|
||||
|
||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||
# file name.
|
||||
|
||||
TRACE_DIR="$OUT_DIR/.traces"
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
if echo "$*" | grep -qF '@@'; then
|
||||
STDIN_FILE="$TRACE_DIR/.cur_input"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# Check for obvious errors.
|
||||
|
||||
if [ ! "$MEM_LIMIT" = "none" ]; then
|
||||
|
||||
if [ "$MEM_LIMIT" -lt "5" ]; then
|
||||
echo "[-] Error: dangerously low memory limit." 1>&2
|
||||
if (timeout && timeout != "none" && timeout < 10) {
|
||||
print "[-] Error: dangerously low timeout." > "/dev/stderr"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fi
|
||||
if (target_bin && !exists_and_is_executable(target_bin)) {
|
||||
|
||||
if [ ! "$TIMEOUT" = "none" ]; then
|
||||
"command -v "target_bin" 2>/dev/null" | getline tnew
|
||||
if (!tnew || !exists_and_is_executable(tnew)) {
|
||||
print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
target_bin = tnew
|
||||
}
|
||||
|
||||
if [ "$TIMEOUT" -lt "10" ]; then
|
||||
echo "[-] Error: dangerously low timeout." 1>&2
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
|
||||
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
|
||||
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != system( "test -d "in_dir )) {
|
||||
print "[-] Error: directory '"in_dir"' not found." > "/dev/stderr"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fi
|
||||
if (0 == system( "test -d "in_dir"/default" )) {
|
||||
in_dir = in_dir "/default"
|
||||
}
|
||||
|
||||
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
||||
if (0 == system( "test -d "in_dir"/queue" )) {
|
||||
in_dir = in_dir "/queue"
|
||||
}
|
||||
|
||||
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
|
||||
system("rm -rf "trace_dir" 2>/dev/null");
|
||||
system("rm "out_dir"/id[:_]* 2>/dev/null")
|
||||
|
||||
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
|
||||
"ls "out_dir"/* 2>/dev/null | wc -l" | getline noofentries
|
||||
if (0 == system( "test -d "out_dir" -a "noofentries" -gt 0" )) {
|
||||
print "[-] Error: directory '"out_dir"' exists and is not empty - delete it first." > "/dev/stderr"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
TARGET_BIN="$TNEW"
|
||||
|
||||
fi
|
||||
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" ]; then
|
||||
|
||||
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
||||
# Check for the more efficient way to copy files...
|
||||
if (0 != system("mkdir -p -m 0700 "trace_dir)) {
|
||||
print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -d "$IN_DIR" ]; then
|
||||
echo "[-] Error: directory '$IN_DIR' not found." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
|
||||
|
||||
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
|
||||
rm -rf "$TRACE_DIR" 2>/dev/null
|
||||
|
||||
rmdir "$OUT_DIR" 2>/dev/null
|
||||
|
||||
if [ -d "$OUT_DIR" ]; then
|
||||
echo "[-] Error: directory '$OUT_DIR' exists and is not empty - delete it first." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -m 700 -p "$TRACE_DIR" || exit 1
|
||||
|
||||
if [ ! "$STDIN_FILE" = "" ]; then
|
||||
rm -f "$STDIN_FILE" || exit 1
|
||||
touch "$STDIN_FILE" || exit 1
|
||||
fi
|
||||
|
||||
if [ "$AFL_PATH" = "" ]; then
|
||||
SHOWMAP="${0%/afl-cmin}/afl-showmap"
|
||||
else
|
||||
SHOWMAP="$AFL_PATH/afl-showmap"
|
||||
fi
|
||||
|
||||
if [ ! -x "$SHOWMAP" ]; then
|
||||
echo "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." 1>&2
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
|
||||
|
||||
if [ "$IN_COUNT" = "0" ]; then
|
||||
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FIRST_FILE=`ls "$IN_DIR" | head -1`
|
||||
|
||||
# Make sure that we're not dealing with a directory.
|
||||
|
||||
if [ -d "$IN_DIR/$FIRST_FILE" ]; then
|
||||
echo "[-] Error: The target directory contains subdirectories - please fix." 1>&2
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for the more efficient way to copy files...
|
||||
|
||||
if ln "$IN_DIR/$FIRST_FILE" "$TRACE_DIR/.link_test" 2>/dev/null; then
|
||||
CP_TOOL=ln
|
||||
else
|
||||
CP_TOOL=cp
|
||||
fi
|
||||
|
||||
# Make sure that we can actually get anything out of afl-showmap before we
|
||||
# waste too much time.
|
||||
|
||||
echo "[*] Testing the target binary..."
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$FIRST_FILE"
|
||||
|
||||
else
|
||||
|
||||
cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
|
||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
fi
|
||||
|
||||
FIRST_COUNT=$((`grep -c . "$TRACE_DIR/.run_test"`))
|
||||
|
||||
if [ "$FIRST_COUNT" -gt "0" ]; then
|
||||
|
||||
echo "[+] OK, $FIRST_COUNT tuples recorded."
|
||||
|
||||
else
|
||||
|
||||
echo "[-] Error: no instrumentation output detected (perhaps crash or timeout)." 1>&2
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
# Let's roll!
|
||||
|
||||
#############################
|
||||
# STEP 1: COLLECTING TRACES #
|
||||
#############################
|
||||
|
||||
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
||||
|
||||
(
|
||||
|
||||
CUR=0
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
|
||||
|
||||
done < <(ls "$IN_DIR")
|
||||
|
||||
else
|
||||
|
||||
while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
done < <(ls "$IN_DIR")
|
||||
|
||||
|
||||
fi
|
||||
|
||||
)
|
||||
|
||||
echo
|
||||
|
||||
##########################
|
||||
# STEP 2: SORTING TUPLES #
|
||||
##########################
|
||||
|
||||
# With this out of the way, we sort all tuples by popularity across all
|
||||
# datasets. The reasoning here is that we won't be able to avoid the files
|
||||
# that trigger unique tuples anyway, so we will want to start with them and
|
||||
# see what's left.
|
||||
|
||||
echo "[*] Sorting trace sets (this may take a while)..."
|
||||
|
||||
ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \
|
||||
sort | uniq -c | sort -k 1,1 -n >"$TRACE_DIR/.all_uniq"
|
||||
|
||||
TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`))
|
||||
|
||||
echo "[+] Found $TUPLE_COUNT unique tuples across $IN_COUNT files."
|
||||
|
||||
#####################################
|
||||
# STEP 3: SELECTING CANDIDATE FILES #
|
||||
#####################################
|
||||
|
||||
# The next step is to find the best candidate for each tuple. The "best"
|
||||
# part is understood simply as the smallest input that includes a particular
|
||||
# tuple in its trace. Empirical evidence suggests that this produces smaller
|
||||
# datasets than more involved algorithms that could be still pulled off in
|
||||
# a shell script.
|
||||
|
||||
echo "[*] Finding best candidates for each tuple..."
|
||||
|
||||
CUR=0
|
||||
|
||||
while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
|
||||
|
||||
done < <(ls -rS "$IN_DIR")
|
||||
|
||||
echo
|
||||
|
||||
##############################
|
||||
# STEP 4: LOADING CANDIDATES #
|
||||
##############################
|
||||
|
||||
# At this point, we have a file of tuple-file pairs, sorted by file size
|
||||
# in ascending order (as a consequence of ls -rS). By doing sort keyed
|
||||
# only by tuple (-k 1,1) and configured to output only the first line for
|
||||
# every key (-s -u), we end up with the smallest file for each tuple.
|
||||
|
||||
echo "[*] Sorting candidate list (be patient)..."
|
||||
|
||||
sort -k1,1 -s -u "$TRACE_DIR/.candidate_list" | \
|
||||
sed 's/^/BEST_FILE[/;s/ /]="/;s/$/"/' >"$TRACE_DIR/.candidate_script"
|
||||
|
||||
if [ ! -s "$TRACE_DIR/.candidate_script" ]; then
|
||||
echo "[-] Error: no traces obtained from test cases, check syntax!" 1>&2
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The sed command converted the sorted list to a shell script that populates
|
||||
# BEST_FILE[tuple]="fname". Let's load that!
|
||||
|
||||
. "$TRACE_DIR/.candidate_script"
|
||||
|
||||
##########################
|
||||
# STEP 5: WRITING OUTPUT #
|
||||
##########################
|
||||
|
||||
# The final trick is to grab the top pick for each tuple, unless said tuple is
|
||||
# already set due to the inclusion of an earlier candidate; and then put all
|
||||
# tuples associated with the newly-added file to the "already have" list. The
|
||||
# loop works from least popular tuples and toward the most common ones.
|
||||
|
||||
echo "[*] Processing candidates and writing output files..."
|
||||
|
||||
CUR=0
|
||||
|
||||
touch "$TRACE_DIR/.already_have"
|
||||
|
||||
while read -r cnt tuple; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing tuple $CUR/$TUPLE_COUNT... "
|
||||
|
||||
# If we already have this tuple, skip it.
|
||||
|
||||
grep -q "^$tuple\$" "$TRACE_DIR/.already_have" && continue
|
||||
|
||||
FN=${BEST_FILE[tuple]}
|
||||
|
||||
$CP_TOOL "$IN_DIR/$FN" "$OUT_DIR/$FN"
|
||||
|
||||
if [ "$((CUR % 5))" = "0" ]; then
|
||||
sort -u "$TRACE_DIR/$FN" "$TRACE_DIR/.already_have" >"$TRACE_DIR/.tmp"
|
||||
mv -f "$TRACE_DIR/.tmp" "$TRACE_DIR/.already_have"
|
||||
else
|
||||
cat "$TRACE_DIR/$FN" >>"$TRACE_DIR/.already_have"
|
||||
fi
|
||||
|
||||
done <"$TRACE_DIR/.all_uniq"
|
||||
|
||||
echo
|
||||
|
||||
OUT_COUNT=`ls -- "$OUT_DIR" | wc -l`
|
||||
|
||||
if [ "$OUT_COUNT" = "1" ]; then
|
||||
echo "[!] WARNING: All test cases had the same traces, check syntax!"
|
||||
fi
|
||||
|
||||
echo "[+] Narrowed down to $OUT_COUNT files, saved in '$OUT_DIR'."
|
||||
echo
|
||||
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (stdin_file) {
|
||||
# truncate input file
|
||||
printf "" > stdin_file
|
||||
close( stdin_file )
|
||||
}
|
||||
|
||||
# First we look in PATH
|
||||
if (0 == system("command -v afl-showmap >/dev/null 2>&1")) {
|
||||
"command -v afl-showmap 2>/dev/null" | getline showmap
|
||||
} else {
|
||||
# then we look in the current directory
|
||||
if (0 == system("test -x ./afl-showmap")) {
|
||||
showmap = "./afl-showmap"
|
||||
} else {
|
||||
if (ENVIRON["AFL_PATH"]) {
|
||||
showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!showmap || 0 != system("test -x "showmap )) {
|
||||
print "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# get list of input filenames sorted by size
|
||||
i = 0
|
||||
# yuck, gnu stat is option incompatible to bsd stat
|
||||
# we use a heuristic to differentiate between
|
||||
# GNU stat and other stats
|
||||
"stat --version 2>/dev/null" | getline statversion
|
||||
if (statversion ~ /GNU coreutils/) {
|
||||
stat_format = "-c '%s %n'" # GNU
|
||||
} else {
|
||||
stat_format = "-f '%z %N'" # *BSD, MacOS
|
||||
}
|
||||
cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)"
|
||||
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
|
||||
while (cmdline | getline) {
|
||||
sub(/^[0-9]+ (\.\/)?/,"",$0)
|
||||
infilesSmallToBig[i++] = $0
|
||||
}
|
||||
in_count = i
|
||||
|
||||
first_file = infilesSmallToBig[0]
|
||||
|
||||
# Make sure that we're not dealing with a directory.
|
||||
|
||||
if (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
|
||||
print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) {
|
||||
cp_tool = "ln"
|
||||
} else {
|
||||
cp_tool = "cp"
|
||||
}
|
||||
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) {
|
||||
# Make sure that we can actually get anything out of afl-showmap before we
|
||||
# waste too much time.
|
||||
|
||||
print "[*] Testing the target binary..."
|
||||
|
||||
if (!stdin_file) {
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
|
||||
} else {
|
||||
system("cp \""in_dir"/"first_file"\" "stdin_file)
|
||||
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
first_count = 0
|
||||
|
||||
runtest = trace_dir"/.run_test"
|
||||
while ((getline < runtest) > 0) {
|
||||
++first_count
|
||||
}
|
||||
|
||||
if (first_count) {
|
||||
print "[+] OK, "first_count" tuples recorded."
|
||||
} else {
|
||||
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Let's roll!
|
||||
|
||||
#############################
|
||||
# STEP 1: Collecting traces #
|
||||
#############################
|
||||
|
||||
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
|
||||
|
||||
cur = 0;
|
||||
if (!stdin_file) {
|
||||
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
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
|
||||
} else {
|
||||
print " Processing "in_count" files (forkserver mode)..."
|
||||
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
|
||||
retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||
}
|
||||
|
||||
if (retval && !AFL_CMIN_CRASHES_ONLY) {
|
||||
print "[!] Exit code "retval" != 0 received from afl-showmap, terminating..."
|
||||
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
system("rmdir "out_dir)
|
||||
}
|
||||
exit retval
|
||||
}
|
||||
|
||||
#######################################################
|
||||
# STEP 2: register smallest input file for each tuple #
|
||||
# STEP 3: copy that file (at most once) #
|
||||
#######################################################
|
||||
|
||||
print "[*] Processing traces for input files in '"in_dir"'."
|
||||
|
||||
cur = 0
|
||||
out_count = 0
|
||||
tuple_count = 0
|
||||
|
||||
# from rare to frequent new tuples
|
||||
# get the best (smallest) file for it
|
||||
# and copy it
|
||||
while (cur < in_count) {
|
||||
fn = infilesSmallToBig[cur]
|
||||
++cur
|
||||
printf "\r Processing file "cur"/"in_count
|
||||
# create path for the trace file from afl-showmap
|
||||
tracefile_path = trace_dir"/"fn
|
||||
# gather all keys, and count them
|
||||
while ((getline line < tracefile_path) > 0) {
|
||||
key = line
|
||||
if (!(key in key_count)) {
|
||||
++tuple_count
|
||||
}
|
||||
++key_count[key]
|
||||
if (! (key in best_file)) {
|
||||
# this is the best file for this key
|
||||
best_file[key] = fn
|
||||
#printf "BEST_FILE[%d]=\"%s\"\n",key,fn | "sort -t'[' -k2 > "trace_dir"/.candidate_script"
|
||||
}
|
||||
#printf "%d %s\n",key,fn > trace_dir"/.candidate_list"
|
||||
}
|
||||
close(tracefile_path)
|
||||
}
|
||||
print ""
|
||||
|
||||
# sort keys
|
||||
sortedKeys = trace_dir"/.all_uniq"
|
||||
sortKeysCmd = "sort -k1n > "sortedKeys
|
||||
for (key in key_count) {
|
||||
printf "%7d %s\n",key_count[key],key | sortKeysCmd
|
||||
}
|
||||
close(sortKeysCmd)
|
||||
|
||||
# iterate over keys from rare to frequent and
|
||||
# copy best file
|
||||
while ((getline < sortedKeys) > 0) {
|
||||
|
||||
# split
|
||||
nrFields = split($0, field, / +/)
|
||||
#print nrFields" Felder: '"field[0]"', '"field[1]"', '"field[2]"', '"field[3]"'"
|
||||
key = field[nrFields]
|
||||
|
||||
++tcnt;
|
||||
printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
|
||||
if (key in keyAlreadyKnown) {
|
||||
continue
|
||||
}
|
||||
|
||||
fn = best_file[key]
|
||||
# gather all tuples from the best file for this key
|
||||
tracedfn = trace_dir"/"fn
|
||||
while ((getline < tracedfn) > 0) {
|
||||
keyAlreadyKnown[$0] = ""
|
||||
}
|
||||
close(tracedfn)
|
||||
|
||||
# copy file unless already done
|
||||
if (! (fn in file_already_copied)) {
|
||||
system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"")
|
||||
file_already_copied[fn] = ""
|
||||
++out_count
|
||||
#printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log"
|
||||
}
|
||||
}
|
||||
close(sortedKeys)
|
||||
print ""
|
||||
print "[+] Found "tuple_count" unique tuples across "in_count" files."
|
||||
|
||||
if (out_count == 1) {
|
||||
print "[!] WARNING: All test cases had the same traces, check syntax!"
|
||||
}
|
||||
print "[+] Narrowed down to "out_count" files, saved in '"out_dir"'."
|
||||
|
||||
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||
system("rm -rf "trace_dir" 2>/dev/null")
|
||||
}
|
||||
|
||||
exit 0
|
||||
}
|
||||
EOF
|
||||
|
492
afl-cmin.bash
Executable file
492
afl-cmin.bash
Executable file
@ -0,0 +1,492 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# american fuzzy lop++ - corpus minimization tool
|
||||
# ---------------------------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2014, 2015 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# This tool tries to find the smallest subset of files in the input directory
|
||||
# that still trigger the full range of instrumentation data points seen in
|
||||
# the starting corpus. This has two uses:
|
||||
#
|
||||
# - Screening large corpora of input files before using them as a seed for
|
||||
# afl-fuzz. The tool will remove functionally redundant files and likely
|
||||
# leave you with a much smaller set.
|
||||
#
|
||||
# (In this case, you probably also want to consider running afl-tmin on
|
||||
# the individual files later on to reduce their size.)
|
||||
#
|
||||
# - Minimizing the corpus generated organically by afl-fuzz, perhaps when
|
||||
# planning to feed it to more resource-intensive tools. The tool achieves
|
||||
# this by removing all entries that used to trigger unique behaviors in the
|
||||
# past, but have been made obsolete by later finds.
|
||||
#
|
||||
# Note that the tool doesn't modify the files themselves. For that, you want
|
||||
# afl-tmin.
|
||||
#
|
||||
# This script must use bash because other shells may have hardcoded limits on
|
||||
# array sizes.
|
||||
#
|
||||
|
||||
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
|
||||
#########
|
||||
# SETUP #
|
||||
#########
|
||||
|
||||
# Process command-line options...
|
||||
|
||||
MEM_LIMIT=none
|
||||
TIMEOUT=none
|
||||
|
||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
|
||||
|
||||
export AFL_QUIET=1
|
||||
|
||||
while getopts "+i:o:f:m:t:eOQUCh" opt; do
|
||||
|
||||
case "$opt" in
|
||||
|
||||
"h")
|
||||
;;
|
||||
|
||||
"i")
|
||||
IN_DIR="$OPTARG"
|
||||
;;
|
||||
|
||||
"o")
|
||||
OUT_DIR="$OPTARG"
|
||||
;;
|
||||
"f")
|
||||
STDIN_FILE="$OPTARG"
|
||||
;;
|
||||
"m")
|
||||
MEM_LIMIT="$OPTARG"
|
||||
MEM_LIMIT_GIVEN=1
|
||||
;;
|
||||
"t")
|
||||
TIMEOUT="$OPTARG"
|
||||
;;
|
||||
"e")
|
||||
EXTRA_PAR="$EXTRA_PAR -e"
|
||||
;;
|
||||
"C")
|
||||
export AFL_CMIN_CRASHES_ONLY=1
|
||||
;;
|
||||
"O")
|
||||
EXTRA_PAR="$EXTRA_PAR -O"
|
||||
FRIDA_MODE=1
|
||||
;;
|
||||
"Q")
|
||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||
QEMU_MODE=1
|
||||
;;
|
||||
"U")
|
||||
EXTRA_PAR="$EXTRA_PAR -U"
|
||||
UNICORN_MODE=1
|
||||
;;
|
||||
"?")
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
TARGET_BIN="$1"
|
||||
|
||||
if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
|
||||
|
||||
cat 1>&2 <<_EOF_
|
||||
Usage: $0 [ options ] -- /path/to/target_app [ ... ]
|
||||
|
||||
Required parameters:
|
||||
|
||||
-i dir - input directory with the starting corpus
|
||||
-o dir - output directory for minimized files
|
||||
|
||||
Execution control settings:
|
||||
|
||||
-f file - location read by the fuzzed program (stdin)
|
||||
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
||||
-t msec - run time limit for child process (none)
|
||||
-O - use binary-only instrumentation (FRIDA mode)
|
||||
-Q - use binary-only instrumentation (QEMU mode)
|
||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||
|
||||
Minimization settings:
|
||||
|
||||
-C - keep crashing inputs, reject everything else
|
||||
-e - solve for edge coverage only, ignore hit counts
|
||||
|
||||
For additional tips, please consult README.md.
|
||||
|
||||
Environment variables used:
|
||||
AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
|
||||
AFL_PATH: last resort location to find the afl-showmap binary
|
||||
AFL_SKIP_BIN_CHECK: skip check for target binary
|
||||
_EOF_
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||
# handle this safely from a shell script.
|
||||
|
||||
#if [ "$AFL_ALLOW_TMP" = "" ]; then
|
||||
#
|
||||
# echo "$IN_DIR" | grep -qE '^(/var)?/tmp/'
|
||||
# T1="$?"
|
||||
#
|
||||
# echo "$TARGET_BIN" | grep -qE '^(/var)?/tmp/'
|
||||
# T2="$?"
|
||||
#
|
||||
# echo "$OUT_DIR" | grep -qE '^(/var)?/tmp/'
|
||||
# T3="$?"
|
||||
#
|
||||
# echo "$STDIN_FILE" | grep -qE '^(/var)?/tmp/'
|
||||
# T4="$?"
|
||||
#
|
||||
# echo "$PWD" | grep -qE '^(/var)?/tmp/'
|
||||
# T5="$?"
|
||||
#
|
||||
# if [ "$T1" = "0" -o "$T2" = "0" -o "$T3" = "0" -o "$T4" = "0" -o "$T5" = "0" ]; then
|
||||
# echo "[-] Error: do not use this script in /tmp or /var/tmp." 1>&2
|
||||
# exit 1
|
||||
# fi
|
||||
#
|
||||
#fi
|
||||
|
||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||
# file name.
|
||||
|
||||
TRACE_DIR="$OUT_DIR/.traces"
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
if echo "$*" | grep -qF '@@'; then
|
||||
STDIN_FILE="$TRACE_DIR/.cur_input"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# Check for obvious errors.
|
||||
|
||||
if [ ! "$MEM_LIMIT" = "none" ]; then
|
||||
|
||||
if [ "$MEM_LIMIT" -lt "5" ]; then
|
||||
echo "[-] Error: dangerously low memory limit." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ ! "$TIMEOUT" = "none" ]; then
|
||||
|
||||
if [ "$TIMEOUT" -lt "10" ]; then
|
||||
echo "[-] Error: dangerously low timeout." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
||||
|
||||
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
|
||||
|
||||
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_BIN="$TNEW"
|
||||
|
||||
fi
|
||||
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||
|
||||
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -d "$IN_DIR" ]; then
|
||||
echo "[-] Error: directory '$IN_DIR' not found." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default"
|
||||
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
|
||||
|
||||
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
|
||||
rm -rf "$TRACE_DIR" 2>/dev/null
|
||||
|
||||
rmdir "$OUT_DIR" 2>/dev/null
|
||||
|
||||
if [ -d "$OUT_DIR" ]; then
|
||||
echo "[-] Error: directory '$OUT_DIR' exists and is not empty - delete it first." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -m 700 -p "$TRACE_DIR" || exit 1
|
||||
|
||||
if [ ! "$STDIN_FILE" = "" ]; then
|
||||
rm -f "$STDIN_FILE" || exit 1
|
||||
touch "$STDIN_FILE" || exit 1
|
||||
fi
|
||||
|
||||
SHOWMAP=`command -v afl-showmap 2>/dev/null`
|
||||
|
||||
if [ -z "$SHOWMAP" ]; then
|
||||
TMP="${0%/afl-cmin.bash}/afl-showmap"
|
||||
if [ -x "$TMP" ]; then
|
||||
SHOWMAP=$TMP
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$SHOWMAP" -a -x "./afl-showmap" ]; then
|
||||
SHOWMAP="./afl-showmap"
|
||||
else
|
||||
if [ -n "$AFL_PATH" ]; then
|
||||
SHOWMAP="$AFL_PATH/afl-showmap"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$SHOWMAP" ]; then
|
||||
echo "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." 1>&2
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
|
||||
|
||||
if [ "$IN_COUNT" = "0" ]; then
|
||||
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FIRST_FILE=`ls "$IN_DIR" | head -1`
|
||||
|
||||
# Make sure that we're not dealing with a directory.
|
||||
|
||||
if [ -d "$IN_DIR/$FIRST_FILE" ]; then
|
||||
echo "[-] Error: The target directory contains subdirectories - please fix." 1>&2
|
||||
rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for the more efficient way to copy files...
|
||||
|
||||
if ln "$IN_DIR/$FIRST_FILE" "$TRACE_DIR/.link_test" 2>/dev/null; then
|
||||
CP_TOOL=ln
|
||||
else
|
||||
CP_TOOL=cp
|
||||
fi
|
||||
|
||||
# Make sure that we can actually get anything out of afl-showmap before we
|
||||
# waste too much time.
|
||||
|
||||
echo "[*] Testing the target binary..."
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$FIRST_FILE"
|
||||
|
||||
else
|
||||
|
||||
cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
|
||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
fi
|
||||
|
||||
FIRST_COUNT=$((`grep -c . "$TRACE_DIR/.run_test"`))
|
||||
|
||||
if [ "$FIRST_COUNT" -gt "0" ]; then
|
||||
|
||||
echo "[+] OK, $FIRST_COUNT tuples recorded."
|
||||
|
||||
else
|
||||
|
||||
echo "[-] Error: no instrumentation output detected (perhaps crash or timeout)." 1>&2
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
# Let's roll!
|
||||
|
||||
#############################
|
||||
# STEP 1: COLLECTING TRACES #
|
||||
#############################
|
||||
|
||||
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
||||
|
||||
(
|
||||
|
||||
CUR=0
|
||||
|
||||
if [ "$STDIN_FILE" = "" ]; then
|
||||
|
||||
ls "$IN_DIR" | while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
|
||||
|
||||
done
|
||||
|
||||
else
|
||||
|
||||
ls "$IN_DIR" | while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
||||
|
||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||
|
||||
done
|
||||
|
||||
|
||||
fi
|
||||
|
||||
)
|
||||
|
||||
echo
|
||||
|
||||
##########################
|
||||
# STEP 2: SORTING TUPLES #
|
||||
##########################
|
||||
|
||||
# With this out of the way, we sort all tuples by popularity across all
|
||||
# datasets. The reasoning here is that we won't be able to avoid the files
|
||||
# that trigger unique tuples anyway, so we will want to start with them and
|
||||
# see what's left.
|
||||
|
||||
echo "[*] Sorting trace sets (this may take a while)..."
|
||||
|
||||
ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \
|
||||
sort | uniq -c | sort -k 1,1 -n >"$TRACE_DIR/.all_uniq"
|
||||
|
||||
TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`))
|
||||
|
||||
echo "[+] Found $TUPLE_COUNT unique tuples across $IN_COUNT files."
|
||||
|
||||
#####################################
|
||||
# STEP 3: SELECTING CANDIDATE FILES #
|
||||
#####################################
|
||||
|
||||
# The next step is to find the best candidate for each tuple. The "best"
|
||||
# part is understood simply as the smallest input that includes a particular
|
||||
# tuple in its trace. Empirical evidence suggests that this produces smaller
|
||||
# datasets than more involved algorithms that could be still pulled off in
|
||||
# a shell script.
|
||||
|
||||
echo "[*] Finding best candidates for each tuple..."
|
||||
|
||||
CUR=0
|
||||
|
||||
ls -rS "$IN_DIR" | while read -r fn; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||
|
||||
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
|
||||
|
||||
done
|
||||
|
||||
echo
|
||||
|
||||
##############################
|
||||
# STEP 4: LOADING CANDIDATES #
|
||||
##############################
|
||||
|
||||
# At this point, we have a file of tuple-file pairs, sorted by file size
|
||||
# in ascending order (as a consequence of ls -rS). By doing sort keyed
|
||||
# only by tuple (-k 1,1) and configured to output only the first line for
|
||||
# every key (-s -u), we end up with the smallest file for each tuple.
|
||||
|
||||
echo "[*] Sorting candidate list (be patient)..."
|
||||
|
||||
sort -k1,1 -s -u "$TRACE_DIR/.candidate_list" | \
|
||||
sed 's/^/BEST_FILE[/;s/ /]="/;s/$/"/' >"$TRACE_DIR/.candidate_script"
|
||||
|
||||
if [ ! -s "$TRACE_DIR/.candidate_script" ]; then
|
||||
echo "[-] Error: no traces obtained from test cases, check syntax!" 1>&2
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The sed command converted the sorted list to a shell script that populates
|
||||
# BEST_FILE[tuple]="fname". Let's load that!
|
||||
|
||||
. "$TRACE_DIR/.candidate_script"
|
||||
|
||||
##########################
|
||||
# STEP 5: WRITING OUTPUT #
|
||||
##########################
|
||||
|
||||
# The final trick is to grab the top pick for each tuple, unless said tuple is
|
||||
# already set due to the inclusion of an earlier candidate; and then put all
|
||||
# tuples associated with the newly-added file to the "already have" list. The
|
||||
# loop works from least popular tuples and toward the most common ones.
|
||||
|
||||
echo "[*] Processing candidates and writing output files..."
|
||||
|
||||
CUR=0
|
||||
|
||||
touch "$TRACE_DIR/.already_have"
|
||||
|
||||
while read -r cnt tuple; do
|
||||
|
||||
CUR=$((CUR+1))
|
||||
printf "\\r Processing tuple $CUR/$TUPLE_COUNT with count $cnt... "
|
||||
|
||||
# If we already have this tuple, skip it.
|
||||
|
||||
grep -q "^$tuple\$" "$TRACE_DIR/.already_have" && continue
|
||||
|
||||
FN=${BEST_FILE[tuple]}
|
||||
|
||||
# echo "tuple nr $CUR ($tuple cnt=$cnt) -> $FN" >> "$TRACE_DIR/.log"
|
||||
$CP_TOOL "$IN_DIR/$FN" "$OUT_DIR/$FN"
|
||||
|
||||
if [ "$((CUR % 5))" = "0" ]; then
|
||||
sort -u "$TRACE_DIR/$FN" "$TRACE_DIR/.already_have" >"$TRACE_DIR/.tmp"
|
||||
mv -f "$TRACE_DIR/.tmp" "$TRACE_DIR/.already_have"
|
||||
else
|
||||
cat "$TRACE_DIR/$FN" >>"$TRACE_DIR/.already_have"
|
||||
fi
|
||||
|
||||
done <"$TRACE_DIR/.all_uniq"
|
||||
|
||||
echo
|
||||
|
||||
OUT_COUNT=`ls -- "$OUT_DIR" | wc -l`
|
||||
|
||||
if [ "$OUT_COUNT" = "1" ]; then
|
||||
echo "[!] WARNING: All test cases had the same traces, check syntax!"
|
||||
fi
|
||||
|
||||
echo "[+] Narrowed down to $OUT_COUNT files, saved in '$OUT_DIR'."
|
||||
echo
|
||||
|
||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||
|
||||
exit 0
|
8271
afl-fuzz.c
8271
afl-fuzz.c
File diff suppressed because it is too large
Load Diff
338
afl-gcc.c
338
afl-gcc.c
@ -1,338 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop - wrapper for GCC and clang
|
||||
----------------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
|
||||
Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This program is a drop-in replacement for GCC or clang. The most common way
|
||||
of using it is to pass the path to afl-gcc or afl-clang via CC when invoking
|
||||
./configure.
|
||||
|
||||
(Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.)
|
||||
|
||||
The wrapper needs to know the path to afl-as (renamed to 'as'). The default
|
||||
is /usr/local/lib/afl/. A convenient way to specify alternative directories
|
||||
would be to set AFL_PATH.
|
||||
|
||||
If AFL_HARDEN is set, the wrapper will compile the target app with various
|
||||
hardening options that may help detect memory management issues more
|
||||
reliably. You can also specify AFL_USE_ASAN to enable ASAN.
|
||||
|
||||
If you want to call a non-default compiler as a next step of the chain,
|
||||
specify its location via AFL_CC or AFL_CXX.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static u8* as_path; /* Path to the AFL 'as' wrapper */
|
||||
static u8** cc_params; /* Parameters passed to the real CC */
|
||||
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
|
||||
static u8 be_quiet, /* Quiet mode */
|
||||
clang_mode; /* Invoked as afl-clang*? */
|
||||
|
||||
|
||||
/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived
|
||||
from argv[0]. If that fails, abort. */
|
||||
|
||||
static void find_as(u8* argv0) {
|
||||
|
||||
u8 *afl_path = getenv("AFL_PATH");
|
||||
u8 *slash, *tmp;
|
||||
|
||||
if (afl_path) {
|
||||
|
||||
tmp = alloc_printf("%s/as", afl_path);
|
||||
|
||||
if (!access(tmp, X_OK)) {
|
||||
as_path = afl_path;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
}
|
||||
|
||||
slash = strrchr(argv0, '/');
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8 *dir;
|
||||
|
||||
*slash = 0;
|
||||
dir = ck_strdup(argv0);
|
||||
*slash = '/';
|
||||
|
||||
tmp = alloc_printf("%s/afl-as", dir);
|
||||
|
||||
if (!access(tmp, X_OK)) {
|
||||
as_path = dir;
|
||||
ck_free(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
ck_free(dir);
|
||||
|
||||
}
|
||||
|
||||
if (!access(AFL_PATH "/as", X_OK)) {
|
||||
as_path = AFL_PATH;
|
||||
return;
|
||||
}
|
||||
|
||||
FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0;
|
||||
u8 *name;
|
||||
|
||||
#if defined(__FreeBSD__) && defined(__x86_64__)
|
||||
u8 m32_set = 0;
|
||||
#endif
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
|
||||
|
||||
name = strrchr(argv[0], '/');
|
||||
if (!name) name = argv[0]; else name++;
|
||||
|
||||
if (!strncmp(name, "afl-clang", 9)) {
|
||||
|
||||
clang_mode = 1;
|
||||
|
||||
setenv(CLANG_ENV_VAR, "1", 1);
|
||||
|
||||
if (!strcmp(name, "afl-clang++")) {
|
||||
u8* alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
|
||||
} else {
|
||||
u8* alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* With GCJ and Eclipse installed, you can actually compile Java! The
|
||||
instrumentation will work (amazingly). Alas, unhandled exceptions do
|
||||
not call abort(), so afl-fuzz would need to be modified to equate
|
||||
non-zero exit codes with crash conditions when working with Java
|
||||
binaries. Meh. */
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX");
|
||||
else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ");
|
||||
else cc_params[0] = getenv("AFL_CC");
|
||||
|
||||
if (!cc_params[0]) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n"
|
||||
" 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n"
|
||||
" set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n");
|
||||
|
||||
FATAL("AFL_CC or AFL_CXX required on MacOS X");
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (!strcmp(name, "afl-g++")) {
|
||||
u8* alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++";
|
||||
} else if (!strcmp(name, "afl-gcj")) {
|
||||
u8* alt_cc = getenv("AFL_GCJ");
|
||||
cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj";
|
||||
} else {
|
||||
u8* alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc";
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
}
|
||||
|
||||
while (--argc) {
|
||||
u8* cur = *(++argv);
|
||||
|
||||
if (!strncmp(cur, "-B", 2)) {
|
||||
|
||||
if (!be_quiet) WARNF("-B is already set, overriding");
|
||||
|
||||
if (!cur[2] && argc > 1) { argc--; argv++; }
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cur, "-integrated-as")) continue;
|
||||
|
||||
if (!strcmp(cur, "-pipe")) continue;
|
||||
|
||||
#if defined(__FreeBSD__) && defined(__x86_64__)
|
||||
if (!strcmp(cur, "-m32")) m32_set = 1;
|
||||
#endif
|
||||
|
||||
if (!strcmp(cur, "-fsanitize=address") ||
|
||||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
|
||||
|
||||
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
||||
|
||||
cc_params[cc_par_cnt++] = cur;
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt++] = "-B";
|
||||
cc_params[cc_par_cnt++] = as_path;
|
||||
|
||||
if (clang_mode)
|
||||
cc_params[cc_par_cnt++] = "-no-integrated-as";
|
||||
|
||||
if (getenv("AFL_HARDEN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fstack-protector-all";
|
||||
|
||||
if (!fortify_set)
|
||||
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
|
||||
|
||||
}
|
||||
|
||||
if (asan_set) {
|
||||
|
||||
/* Pass this on to afl-as to adjust map density. */
|
||||
|
||||
setenv("AFL_USE_ASAN", "1", 1);
|
||||
|
||||
} else if (getenv("AFL_USE_ASAN")) {
|
||||
|
||||
if (getenv("AFL_USE_MSAN"))
|
||||
FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
if (getenv("AFL_HARDEN"))
|
||||
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=address";
|
||||
|
||||
} else if (getenv("AFL_USE_MSAN")) {
|
||||
|
||||
if (getenv("AFL_USE_ASAN"))
|
||||
FATAL("ASAN and MSAN are mutually exclusive");
|
||||
|
||||
if (getenv("AFL_HARDEN"))
|
||||
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
|
||||
|
||||
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
|
||||
cc_params[cc_par_cnt++] = "-fsanitize=memory";
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
||||
|
||||
#if defined(__FreeBSD__) && defined(__x86_64__)
|
||||
|
||||
/* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself
|
||||
works OK. This has nothing to do with us, but let's avoid triggering
|
||||
that bug. */
|
||||
|
||||
if (!clang_mode || !m32_set)
|
||||
cc_params[cc_par_cnt++] = "-g";
|
||||
|
||||
#else
|
||||
|
||||
cc_params[cc_par_cnt++] = "-g";
|
||||
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt++] = "-O3";
|
||||
cc_params[cc_par_cnt++] = "-funroll-loops";
|
||||
|
||||
/* Two indicators that you're building for fuzzing; one of them is
|
||||
AFL-specific, the other is shared with libfuzzer. */
|
||||
|
||||
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
|
||||
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_NO_BUILTIN")) {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
|
||||
cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
|
||||
|
||||
}
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
|
||||
SAYF(cCYA "afl-cc" VERSION cRST " by <lcamtuf@google.com>\n");
|
||||
|
||||
} else be_quiet = 1;
|
||||
|
||||
if (argc < 2) {
|
||||
|
||||
SAYF("\n"
|
||||
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n"
|
||||
"for gcc or clang, letting you recompile third-party code with the required\n"
|
||||
"runtime instrumentation. A common use pattern would be one of the following:\n\n"
|
||||
|
||||
" CC=%s/afl-gcc ./configure\n"
|
||||
" CXX=%s/afl-g++ ./configure\n\n"
|
||||
|
||||
"You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n"
|
||||
"Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
|
||||
BIN_PATH, BIN_PATH);
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
find_as(argv[0]);
|
||||
|
||||
edit_params(argc, argv);
|
||||
|
||||
execvp(cc_params[0], (char**)cc_params);
|
||||
|
||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
109
afl-plot
109
afl-plot
@ -1,9 +1,9 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop - Advanced Persistent Graphing
|
||||
# american fuzzy lop++ - Advanced Persistent Graphing
|
||||
# -------------------------------------------------
|
||||
#
|
||||
# Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
# Originally written by Michal Zalewski
|
||||
# Based on a design & prototype by Michael Rash.
|
||||
#
|
||||
# Copyright 2014, 2015 Google Inc. All rights reserved.
|
||||
@ -15,58 +15,73 @@
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
echo "progress plotting utility for afl-fuzz by <lcamtuf@google.com>"
|
||||
get_abs_path() {
|
||||
echo $(cd "`dirname "$1"`" && pwd)/"`basename "$1"`"
|
||||
}
|
||||
|
||||
echo "progress plotting utility for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
|
||||
if [ ! "$#" = "2" ]; then
|
||||
|
||||
cat 1>&2 <<_EOF_
|
||||
This program generates gnuplot images from afl-fuzz output data. Usage:
|
||||
|
||||
$0 afl_state_dir graph_output_dir
|
||||
|
||||
This program generates gnuplot images from afl-fuzz output data. Usage:
|
||||
|
||||
The afl_state_dir parameter should point to an existing state directory for any
|
||||
active or stopped instance of afl-fuzz; while graph_output_dir should point to
|
||||
an empty directory where this tool can write the resulting plots to.
|
||||
|
||||
The program will put index.html and three PNG images in the output directory;
|
||||
you should be able to view it with any web browser of your choice.
|
||||
|
||||
_EOF_
|
||||
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
if [ "$AFL_ALLOW_TMP" = "" ]; then
|
||||
inputdir=`get_abs_path "$1"`
|
||||
outputdir=`get_abs_path "$2"`
|
||||
|
||||
echo "$1" | grep -qE '^(/var)?/tmp/'
|
||||
T1="$?"
|
||||
#if [ "$AFL_ALLOW_TMP" = "" ]; then
|
||||
#
|
||||
# echo "$inputdir" | grep -qE '^(/var)?/tmp/'
|
||||
# T1="$?"
|
||||
#
|
||||
# echo "$outputdir" | grep -qE '^(/var)?/tmp/'
|
||||
# T2="$?"
|
||||
#
|
||||
# if [ "$T1" = "0" -o "$T2" = "0" ]; then
|
||||
#
|
||||
# echo "[-] Error: this script shouldn't be used with shared /tmp directories." 1>&2
|
||||
# exit 1
|
||||
#
|
||||
# fi
|
||||
#
|
||||
#fi
|
||||
|
||||
echo "$2" | grep -qE '^(/var)?/tmp/'
|
||||
T2="$?"
|
||||
|
||||
if [ "$T1" = "0" -o "$T2" = "0" ]; then
|
||||
|
||||
echo "[-] Error: this script shouldn't be used with shared /tmp directories." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ ! -f "$1/plot_data" ]; then
|
||||
if [ ! -f "$inputdir/plot_data" ]; then
|
||||
|
||||
echo "[-] Error: input directory is not valid (missing 'plot_data')." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
BANNER="`cat "$1/fuzzer_stats" | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
|
||||
LINES=`cat "$inputdir/plot_data" | wc -l`
|
||||
|
||||
if [ "$LINES" -lt 3 ]; then
|
||||
|
||||
echo "[-] Error: plot_data carries too little data, let it run longer." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
BANNER="`cat "$inputdir/fuzzer_stats" 2> /dev/null | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
|
||||
|
||||
test "$BANNER" = "" && BANNER="(none)"
|
||||
|
||||
GNUPLOT=`which gnuplot 2>/dev/null`
|
||||
GNUPLOT=`command -v gnuplot 2>/dev/null`
|
||||
|
||||
if [ "$GNUPLOT" = "" ]; then
|
||||
|
||||
@ -75,17 +90,17 @@ if [ "$GNUPLOT" = "" ]; then
|
||||
|
||||
fi
|
||||
|
||||
mkdir "$2" 2>/dev/null
|
||||
mkdir "$outputdir" 2>/dev/null
|
||||
|
||||
if [ ! -d "$2" ]; then
|
||||
if [ ! -d "$outputdir" ]; then
|
||||
|
||||
echo "[-] Error: unable to create the output directory - pick another location." 1>&2
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
rm -f "$2/high_freq.png" "$2/low_freq.png" "$2/exec_speed.png"
|
||||
mv -f "$2/index.html" "$2/index.html.orig" 2>/dev/null
|
||||
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
|
||||
mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
|
||||
|
||||
echo "[*] Generating plots..."
|
||||
|
||||
@ -94,11 +109,11 @@ echo "[*] Generating plots..."
|
||||
cat <<_EOF_
|
||||
set terminal png truecolor enhanced size 1000,300 butt
|
||||
|
||||
set output '$2/high_freq.png'
|
||||
set output '$outputdir/high_freq.png'
|
||||
|
||||
set xdata time
|
||||
set timefmt '%s'
|
||||
set format x "%b %d\n%H:%M"
|
||||
#set xdata time
|
||||
#set timefmt '%s'
|
||||
#set format x "%b %d\n%H:%M"
|
||||
set tics font 'small'
|
||||
unset mxtics
|
||||
unset mytics
|
||||
@ -112,31 +127,38 @@ set key outside
|
||||
set autoscale xfixmin
|
||||
set autoscale xfixmax
|
||||
|
||||
plot '$1/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
|
||||
#set xlabel "all times in UTC" font "small"
|
||||
|
||||
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
|
||||
'' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
|
||||
'' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
|
||||
'' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3
|
||||
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$2/low_freq.png'
|
||||
set output '$outputdir/low_freq.png'
|
||||
|
||||
plot '$1/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
|
||||
plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
|
||||
'' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
|
||||
'' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
|
||||
'' using 1:10 with lines title 'levels' linecolor rgb '#0090ff' linewidth 3
|
||||
|
||||
set terminal png truecolor enhanced size 1000,200 butt
|
||||
set output '$2/exec_speed.png'
|
||||
set output '$outputdir/exec_speed.png'
|
||||
|
||||
plot '$1/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
|
||||
'$1/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
|
||||
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
|
||||
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
|
||||
|
||||
set terminal png truecolor enhanced size 1000,300 butt
|
||||
set output '$outputdir/edges.png'
|
||||
|
||||
plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
|
||||
|
||||
_EOF_
|
||||
|
||||
) | gnuplot
|
||||
|
||||
if [ ! -s "$2/exec_speed.png" ]; then
|
||||
if [ ! -s "$outputdir/exec_speed.png" ]; then
|
||||
|
||||
echo "[-] Error: something went wrong! Perhaps you have an ancient version of gnuplot?" 1>&2
|
||||
exit 1
|
||||
@ -145,13 +167,14 @@ fi
|
||||
|
||||
echo "[*] Generating index.html..."
|
||||
|
||||
cat >"$2/index.html" <<_EOF_
|
||||
cat >"$outputdir/index.html" <<_EOF_
|
||||
<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
|
||||
<tr><td style="width: 18ex"><b>Banner:</b></td><td>$BANNER</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>$1</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>$inputdir</td></tr>
|
||||
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="edges.png" width=1000 height=300>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
@ -162,8 +185,8 @@ _EOF_
|
||||
# served by Apache or other HTTP daemon. Since the plots aren't horribly
|
||||
# sensitive, this seems like a reasonable trade-off.
|
||||
|
||||
chmod 755 "$2"
|
||||
chmod 644 "$2/high_freq.png" "$2/low_freq.png" "$2/exec_speed.png" "$2/index.html"
|
||||
chmod 755 "$outputdir"
|
||||
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!"
|
||||
|
||||
|
777
afl-showmap.c
777
afl-showmap.c
@ -1,777 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop - map display utility
|
||||
----------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
|
||||
Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
A very simple tool that runs the targeted binary and displays
|
||||
the contents of the trace bitmap in a human-readable form. Useful in
|
||||
scripts to eliminate redundant inputs and perform other checks.
|
||||
|
||||
Exit code is 2 if the target program crashes; 1 if it times out or
|
||||
there is a problem executing it; or 0 if execution is successful.
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static s32 child_pid; /* PID of the tested program */
|
||||
|
||||
static u8* trace_bits; /* SHM with instrumentation bitmap */
|
||||
|
||||
static u8 *out_file, /* Trace output file */
|
||||
*doc_path, /* Path to docs */
|
||||
*target_path, /* Path to target binary */
|
||||
*at_file; /* Substitution string for @@ */
|
||||
|
||||
static u32 exec_tmout; /* Exec timeout (ms) */
|
||||
|
||||
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
|
||||
|
||||
static s32 shm_id; /* ID of the SHM region */
|
||||
|
||||
static u8 quiet_mode, /* Hide non-essential messages? */
|
||||
edges_only, /* Ignore hit counts? */
|
||||
cmin_mode, /* Generate output in afl-cmin mode? */
|
||||
binary_mode, /* Write output as a binary map */
|
||||
keep_cores; /* Allow coredumps? */
|
||||
|
||||
static volatile u8
|
||||
stop_soon, /* Ctrl-C pressed? */
|
||||
child_timed_out, /* Child timed out? */
|
||||
child_crashed; /* Child crashed? */
|
||||
|
||||
/* Classify tuple counts. Instead of mapping to individual bits, as in
|
||||
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
|
||||
|
||||
static const u8 count_class_human[256] = {
|
||||
|
||||
[0] = 0,
|
||||
[1] = 1,
|
||||
[2] = 2,
|
||||
[3] = 3,
|
||||
[4 ... 7] = 4,
|
||||
[8 ... 15] = 5,
|
||||
[16 ... 31] = 6,
|
||||
[32 ... 127] = 7,
|
||||
[128 ... 255] = 8
|
||||
|
||||
};
|
||||
|
||||
static const u8 count_class_binary[256] = {
|
||||
|
||||
[0] = 0,
|
||||
[1] = 1,
|
||||
[2] = 2,
|
||||
[3] = 4,
|
||||
[4 ... 7] = 8,
|
||||
[8 ... 15] = 16,
|
||||
[16 ... 31] = 32,
|
||||
[32 ... 127] = 64,
|
||||
[128 ... 255] = 128
|
||||
|
||||
};
|
||||
|
||||
static void classify_counts(u8* mem, const u8* map) {
|
||||
|
||||
u32 i = MAP_SIZE;
|
||||
|
||||
if (edges_only) {
|
||||
|
||||
while (i--) {
|
||||
if (*mem) *mem = 1;
|
||||
mem++;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
while (i--) {
|
||||
*mem = map[*mem];
|
||||
mem++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Get rid of shared memory (atexit handler). */
|
||||
|
||||
static void remove_shm(void) {
|
||||
|
||||
shmctl(shm_id, IPC_RMID, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Configure shared memory. */
|
||||
|
||||
static void setup_shm(void) {
|
||||
|
||||
u8* shm_str;
|
||||
|
||||
shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
|
||||
|
||||
if (shm_id < 0) PFATAL("shmget() failed");
|
||||
|
||||
atexit(remove_shm);
|
||||
|
||||
shm_str = alloc_printf("%d", shm_id);
|
||||
|
||||
setenv(SHM_ENV_VAR, shm_str, 1);
|
||||
|
||||
ck_free(shm_str);
|
||||
|
||||
trace_bits = shmat(shm_id, NULL, 0);
|
||||
|
||||
if (!trace_bits) PFATAL("shmat() failed");
|
||||
|
||||
}
|
||||
|
||||
/* Write results. */
|
||||
|
||||
static u32 write_results(void) {
|
||||
|
||||
s32 fd;
|
||||
u32 i, ret = 0;
|
||||
|
||||
u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
|
||||
caa = !!getenv("AFL_CMIN_ALLOW_ANY");
|
||||
|
||||
if (!strncmp(out_file, "/dev/", 5)) {
|
||||
|
||||
fd = open(out_file, O_WRONLY, 0600);
|
||||
if (fd < 0) PFATAL("Unable to open '%s'", out_file);
|
||||
|
||||
} else if (!strcmp(out_file, "-")) {
|
||||
|
||||
fd = dup(1);
|
||||
if (fd < 0) PFATAL("Unable to open stdout");
|
||||
|
||||
} else {
|
||||
|
||||
unlink(out_file); /* Ignore errors */
|
||||
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0) PFATAL("Unable to create '%s'", out_file);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (binary_mode) {
|
||||
|
||||
for (i = 0; i < MAP_SIZE; i++)
|
||||
if (trace_bits[i]) ret++;
|
||||
|
||||
ck_write(fd, trace_bits, MAP_SIZE, out_file);
|
||||
close(fd);
|
||||
|
||||
} else {
|
||||
|
||||
FILE* f = fdopen(fd, "w");
|
||||
|
||||
if (!f) PFATAL("fdopen() failed");
|
||||
|
||||
for (i = 0; i < MAP_SIZE; i++) {
|
||||
|
||||
if (!trace_bits[i]) continue;
|
||||
ret++;
|
||||
|
||||
if (cmin_mode) {
|
||||
|
||||
if (child_timed_out) break;
|
||||
if (!caa && child_crashed != cco) break;
|
||||
|
||||
fprintf(f, "%u%u\n", trace_bits[i], i);
|
||||
|
||||
} else fprintf(f, "%06u:%u\n", i, trace_bits[i]);
|
||||
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Handle timeout signal. */
|
||||
|
||||
static void handle_timeout(int sig) {
|
||||
|
||||
child_timed_out = 1;
|
||||
if (child_pid > 0) kill(child_pid, SIGKILL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Execute target application. */
|
||||
|
||||
static void run_target(char** argv) {
|
||||
|
||||
static struct itimerval it;
|
||||
int status = 0;
|
||||
|
||||
if (!quiet_mode)
|
||||
SAYF("-- Program output begins --\n" cRST);
|
||||
|
||||
MEM_BARRIER();
|
||||
|
||||
child_pid = fork();
|
||||
|
||||
if (child_pid < 0) PFATAL("fork() failed");
|
||||
|
||||
if (!child_pid) {
|
||||
|
||||
struct rlimit r;
|
||||
|
||||
if (quiet_mode) {
|
||||
|
||||
s32 fd = open("/dev/null", O_RDWR);
|
||||
|
||||
if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
|
||||
*(u32*)trace_bits = EXEC_FAIL_SIG;
|
||||
PFATAL("Descriptor initialization failed");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
|
||||
if (mem_limit) {
|
||||
|
||||
r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
|
||||
|
||||
#ifdef RLIMIT_AS
|
||||
|
||||
setrlimit(RLIMIT_AS, &r); /* Ignore errors */
|
||||
|
||||
#else
|
||||
|
||||
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
|
||||
|
||||
#endif /* ^RLIMIT_AS */
|
||||
|
||||
}
|
||||
|
||||
if (!keep_cores) r.rlim_max = r.rlim_cur = 0;
|
||||
else r.rlim_max = r.rlim_cur = RLIM_INFINITY;
|
||||
|
||||
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
|
||||
|
||||
if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
|
||||
|
||||
setsid();
|
||||
|
||||
execv(target_path, argv);
|
||||
|
||||
*(u32*)trace_bits = EXEC_FAIL_SIG;
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
/* Configure timeout, wait for child, cancel timeout. */
|
||||
|
||||
if (exec_tmout) {
|
||||
|
||||
child_timed_out = 0;
|
||||
it.it_value.tv_sec = (exec_tmout / 1000);
|
||||
it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
|
||||
|
||||
}
|
||||
|
||||
setitimer(ITIMER_REAL, &it, NULL);
|
||||
|
||||
if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
|
||||
|
||||
child_pid = 0;
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &it, NULL);
|
||||
|
||||
MEM_BARRIER();
|
||||
|
||||
/* Clean up bitmap, analyze exit condition, etc. */
|
||||
|
||||
if (*(u32*)trace_bits == EXEC_FAIL_SIG)
|
||||
FATAL("Unable to execute '%s'", argv[0]);
|
||||
|
||||
classify_counts(trace_bits, binary_mode ?
|
||||
count_class_binary : count_class_human);
|
||||
|
||||
if (!quiet_mode)
|
||||
SAYF(cRST "-- Program output ends --\n");
|
||||
|
||||
if (!child_timed_out && !stop_soon && WIFSIGNALED(status))
|
||||
child_crashed = 1;
|
||||
|
||||
if (!quiet_mode) {
|
||||
|
||||
if (child_timed_out)
|
||||
SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
|
||||
else if (stop_soon)
|
||||
SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
|
||||
else if (child_crashed)
|
||||
SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Handle Ctrl-C and the like. */
|
||||
|
||||
static void handle_stop_sig(int sig) {
|
||||
|
||||
stop_soon = 1;
|
||||
|
||||
if (child_pid > 0) kill(child_pid, SIGKILL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Do basic preparations - persistent fds, filenames, etc. */
|
||||
|
||||
static void set_up_environment(void) {
|
||||
|
||||
setenv("ASAN_OPTIONS", "abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
"symbolize=0:"
|
||||
"allocator_may_return_null=1", 0);
|
||||
|
||||
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
|
||||
"symbolize=0:"
|
||||
"abort_on_error=1:"
|
||||
"allocator_may_return_null=1:"
|
||||
"msan_track_origins=0", 0);
|
||||
|
||||
if (getenv("AFL_PRELOAD")) {
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Setup signal handlers, duh. */
|
||||
|
||||
static void setup_signal_handlers(void) {
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = NULL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_sigaction = NULL;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
/* Various ways of saying "stop". */
|
||||
|
||||
sa.sa_handler = handle_stop_sig;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
|
||||
/* Exec timeout notifications. */
|
||||
|
||||
sa.sa_handler = handle_timeout;
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Detect @@ in args. */
|
||||
|
||||
static void detect_file_args(char** argv) {
|
||||
|
||||
u32 i = 0;
|
||||
u8* cwd = getcwd(NULL, 0);
|
||||
|
||||
if (!cwd) PFATAL("getcwd() failed");
|
||||
|
||||
while (argv[i]) {
|
||||
|
||||
u8* aa_loc = strstr(argv[i], "@@");
|
||||
|
||||
if (aa_loc) {
|
||||
|
||||
u8 *aa_subst, *n_arg;
|
||||
|
||||
if (!at_file) FATAL("@@ syntax is not supported by this tool.");
|
||||
|
||||
/* Be sure that we're always using fully-qualified paths. */
|
||||
|
||||
if (at_file[0] == '/') aa_subst = at_file;
|
||||
else aa_subst = alloc_printf("%s/%s", cwd, at_file);
|
||||
|
||||
/* Construct a replacement argv value. */
|
||||
|
||||
*aa_loc = 0;
|
||||
n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
|
||||
argv[i] = n_arg;
|
||||
*aa_loc = '@';
|
||||
|
||||
if (at_file[0] != '/') ck_free(aa_subst);
|
||||
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
free(cwd); /* not tracked */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Show banner. */
|
||||
|
||||
static void show_banner(void) {
|
||||
|
||||
SAYF(cCYA "afl-showmap" VERSION cRST " by <lcamtuf@google.com>\n");
|
||||
|
||||
}
|
||||
|
||||
/* Display usage hints. */
|
||||
|
||||
static void usage(u8* argv0) {
|
||||
|
||||
show_banner();
|
||||
|
||||
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
|
||||
|
||||
"Required parameters:\n\n"
|
||||
|
||||
" -o file - file to write the trace data to\n\n"
|
||||
|
||||
"Execution control settings:\n\n"
|
||||
|
||||
" -t msec - timeout for each run (none)\n"
|
||||
" -m megs - memory limit for child process (%u MB)\n"
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n\n"
|
||||
|
||||
"Other settings:\n\n"
|
||||
|
||||
" -q - sink program's output and don't show messages\n"
|
||||
" -e - show edge coverage only, ignore hit counts\n"
|
||||
" -c - allow core dumps\n\n"
|
||||
|
||||
"This tool displays raw tuple data captured by AFL instrumentation.\n"
|
||||
"For additional help, consult %s/README.\n\n" cRST,
|
||||
|
||||
argv0, MEM_LIMIT, doc_path);
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Find binary. */
|
||||
|
||||
static void find_binary(u8* fname) {
|
||||
|
||||
u8* env_path = 0;
|
||||
struct stat st;
|
||||
|
||||
if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
|
||||
|
||||
target_path = ck_strdup(fname);
|
||||
|
||||
if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
|
||||
!(st.st_mode & 0111) || st.st_size < 4)
|
||||
FATAL("Program '%s' not found or not executable", fname);
|
||||
|
||||
} else {
|
||||
|
||||
while (env_path) {
|
||||
|
||||
u8 *cur_elem, *delim = strchr(env_path, ':');
|
||||
|
||||
if (delim) {
|
||||
|
||||
cur_elem = ck_alloc(delim - env_path + 1);
|
||||
memcpy(cur_elem, env_path, delim - env_path);
|
||||
delim++;
|
||||
|
||||
} else cur_elem = ck_strdup(env_path);
|
||||
|
||||
env_path = delim;
|
||||
|
||||
if (cur_elem[0])
|
||||
target_path = alloc_printf("%s/%s", cur_elem, fname);
|
||||
else
|
||||
target_path = ck_strdup(fname);
|
||||
|
||||
ck_free(cur_elem);
|
||||
|
||||
if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
|
||||
(st.st_mode & 0111) && st.st_size >= 4) break;
|
||||
|
||||
ck_free(target_path);
|
||||
target_path = 0;
|
||||
|
||||
}
|
||||
|
||||
if (!target_path) FATAL("Program '%s' not found or not executable", fname);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Fix up argv for QEMU. */
|
||||
|
||||
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
|
||||
|
||||
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
|
||||
u8 *tmp, *cp, *rsl, *own_copy;
|
||||
|
||||
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
|
||||
|
||||
new_argv[2] = target_path;
|
||||
new_argv[1] = "--";
|
||||
|
||||
/* Now we need to actually find qemu for argv[0]. */
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK))
|
||||
FATAL("Unable to find '%s'", tmp);
|
||||
|
||||
target_path = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
target_path = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
} else ck_free(own_copy);
|
||||
|
||||
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
|
||||
|
||||
target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
FATAL("Unable to find 'afl-qemu-trace'.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
s32 opt;
|
||||
u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
|
||||
u32 tcnt;
|
||||
char** use_argv;
|
||||
|
||||
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
|
||||
|
||||
while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQbc")) > 0)
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'o':
|
||||
|
||||
if (out_file) FATAL("Multiple -o options not supported");
|
||||
out_file = optarg;
|
||||
break;
|
||||
|
||||
case 'm': {
|
||||
|
||||
u8 suffix = 'M';
|
||||
|
||||
if (mem_limit_given) FATAL("Multiple -m options not supported");
|
||||
mem_limit_given = 1;
|
||||
|
||||
if (!strcmp(optarg, "none")) {
|
||||
|
||||
mem_limit = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
|
||||
optarg[0] == '-') FATAL("Bad syntax used for -m");
|
||||
|
||||
switch (suffix) {
|
||||
|
||||
case 'T': mem_limit *= 1024 * 1024; break;
|
||||
case 'G': mem_limit *= 1024; break;
|
||||
case 'k': mem_limit /= 1024; break;
|
||||
case 'M': break;
|
||||
|
||||
default: FATAL("Unsupported suffix or bad syntax for -m");
|
||||
|
||||
}
|
||||
|
||||
if (mem_limit < 5) FATAL("Dangerously low value of -m");
|
||||
|
||||
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
|
||||
FATAL("Value of -m out of range on 32-bit systems");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 't':
|
||||
|
||||
if (timeout_given) FATAL("Multiple -t options not supported");
|
||||
timeout_given = 1;
|
||||
|
||||
if (strcmp(optarg, "none")) {
|
||||
exec_tmout = atoi(optarg);
|
||||
|
||||
if (exec_tmout < 20 || optarg[0] == '-')
|
||||
FATAL("Dangerously low value of -t");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
|
||||
if (edges_only) FATAL("Multiple -e options not supported");
|
||||
edges_only = 1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
|
||||
if (quiet_mode) FATAL("Multiple -q options not supported");
|
||||
quiet_mode = 1;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
|
||||
/* This is an undocumented option to write data in the syntax expected
|
||||
by afl-cmin. Nobody else should have any use for this. */
|
||||
|
||||
cmin_mode = 1;
|
||||
quiet_mode = 1;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
|
||||
/* Another afl-cmin specific feature. */
|
||||
at_file = optarg;
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
|
||||
if (qemu_mode) FATAL("Multiple -Q options not supported");
|
||||
if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
|
||||
|
||||
qemu_mode = 1;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
|
||||
/* Secret undocumented mode. Writes output in raw binary format
|
||||
similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
|
||||
|
||||
binary_mode = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
|
||||
if (keep_cores) FATAL("Multiple -c options not supported");
|
||||
keep_cores = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
usage(argv[0]);
|
||||
|
||||
}
|
||||
|
||||
if (optind == argc || !out_file) usage(argv[0]);
|
||||
|
||||
setup_shm();
|
||||
setup_signal_handlers();
|
||||
|
||||
set_up_environment();
|
||||
|
||||
find_binary(argv[optind]);
|
||||
|
||||
if (!quiet_mode) {
|
||||
show_banner();
|
||||
ACTF("Executing '%s'...\n", target_path);
|
||||
}
|
||||
|
||||
detect_file_args(argv + optind);
|
||||
|
||||
if (qemu_mode)
|
||||
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
|
||||
else
|
||||
use_argv = argv + optind;
|
||||
|
||||
run_target(use_argv);
|
||||
|
||||
tcnt = write_results();
|
||||
|
||||
if (!quiet_mode) {
|
||||
|
||||
if (!tcnt) FATAL("No instrumentation detected" cRST);
|
||||
OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file);
|
||||
|
||||
}
|
||||
|
||||
exit(child_crashed * 2 + child_timed_out);
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,131 @@
|
||||
#!/bin/sh
|
||||
echo This reconfigures the system to have a better fuzzing performance
|
||||
sysctl -w kernel.core_pattern=core
|
||||
sysctl -w kernel.randomize_va_space=0
|
||||
sysctl -w kernel.sched_child_runs_first=1
|
||||
sysctl -w kernel.sched_autogroup_enabled=1
|
||||
sysctl -w kernel.sched_migration_cost_ns=50000000
|
||||
sysctl -w kernel.sched_latency_ns=250000000
|
||||
echo never > /sys/kernel/mm/transparent_hugepage/enabled
|
||||
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
|
||||
echo
|
||||
echo $0
|
||||
echo
|
||||
echo afl-system-config has no command line options
|
||||
echo
|
||||
echo afl-system reconfigures the system to a high performance fuzzing state
|
||||
echo "WARNING: this reduces the security of the system!"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
DONE=
|
||||
PLATFORM=`uname -s`
|
||||
echo This reconfigures the system to have a better fuzzing performance.
|
||||
echo "WARNING: this reduces the security of the system!"
|
||||
echo
|
||||
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 '/etc/default/grub: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"'
|
||||
echo
|
||||
echo Also use AFL_TMPDIR to use a tmpfs for the input file
|
||||
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
|
||||
echo "Warning: you need to be root to run this!"
|
||||
# we do not exit as other mechanisms exist that allows to do this than
|
||||
# being root. let the errors speak for themselves.
|
||||
fi
|
||||
sleep 1
|
||||
if [ "$PLATFORM" = "Linux" ] ; then
|
||||
{
|
||||
sysctl -w kernel.core_uses_pid=0
|
||||
# Arch Linux requires core_pattern to be empty :(
|
||||
test -e /etc/arch-release && sysctl -w kernel.core_pattern=
|
||||
test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
|
||||
sysctl -w kernel.randomize_va_space=0
|
||||
sysctl -w kernel.sched_child_runs_first=1
|
||||
sysctl -w kernel.sched_autogroup_enabled=1
|
||||
sysctl -w kernel.sched_migration_cost_ns=50000000
|
||||
sysctl -w kernel.sched_latency_ns=250000000
|
||||
echo never > /sys/kernel/mm/transparent_hugepage/enabled
|
||||
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
|
||||
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/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/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
|
||||
test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
||||
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 ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 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 srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
|
||||
echo
|
||||
}
|
||||
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "FreeBSD" ] ; then
|
||||
{
|
||||
sysctl kern.elf32.aslr.enable=0
|
||||
sysctl kern.elf64.aslr.enable=0
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||
echo ' sysctl hw.ibrs_disable=1'
|
||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "OpenBSD" ] ; then
|
||||
echo 'System security features cannot be disabled on OpenBSD.'
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "DragonFly" ] ; then
|
||||
#/sbin/sysctl kern.corefile=/dev/null
|
||||
#echo Settings applied.
|
||||
cat <<EOF
|
||||
In order to suppress core file generation during fuzzing it is recommended to set
|
||||
me:\\
|
||||
:coredumpsize=0:
|
||||
in the ~/.login_conf file for the user used for fuzzing.
|
||||
EOF
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "NetBSD" ] ; then
|
||||
{
|
||||
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
|
||||
} > /dev/null
|
||||
echo Settings applied.
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
sysctl kern.sysv.shmmax=8388608
|
||||
sysctl kern.sysv.shmseg=48
|
||||
sysctl kern.sysv.shmall=98304
|
||||
echo Settings applied.
|
||||
echo
|
||||
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
|
||||
echo
|
||||
echo Unloading the default crash reporter
|
||||
SL=/System/Library; PL=com.apple.ReportCrash
|
||||
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1
|
||||
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
|
||||
echo
|
||||
fi
|
||||
echo It is recommended to disable System Integration Protection for increased performance.
|
||||
echo
|
||||
DONE=1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Haiku" ] ; then
|
||||
DEBUG_SERVER_DIR=~/config/settings/system/debug_server
|
||||
[ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR}
|
||||
SETTINGS=${DEBUG_SERVER_DIR}/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.; echo; \
|
||||
}
|
||||
DONE=1
|
||||
fi
|
||||
test -z "$DONE" && echo Error: Unknown platform: $PLATFORM
|
||||
exit 0
|
||||
|
1152
afl-tmin.c
1152
afl-tmin.c
File diff suppressed because it is too large
Load Diff
188
afl-whatsup
188
afl-whatsup
@ -1,11 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop - status check tool
|
||||
# --------------------------------------
|
||||
# american fuzzy lop++ - status check tool
|
||||
# ----------------------------------------
|
||||
#
|
||||
# Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -17,27 +18,44 @@
|
||||
# instances of afl-fuzz.
|
||||
#
|
||||
|
||||
echo "status check tool for afl-fuzz by <lcamtuf@google.com>"
|
||||
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo "Usage: $0 [-s] [-d] afl_output_directory"
|
||||
echo
|
||||
echo Options:
|
||||
echo " -s - skip details and output summary results only"
|
||||
echo " -d - include dead fuzzer stats"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$1" = "-s" ]; then
|
||||
unset SUMMARY_ONLY
|
||||
unset PROCESS_DEAD
|
||||
|
||||
SUMMARY_ONLY=1
|
||||
DIR="$2"
|
||||
while [ "$1" = "-s" -o "$1" = "-d" ]; do
|
||||
|
||||
else
|
||||
if [ "$1" = "-s" ]; then
|
||||
SUMMARY_ONLY=1
|
||||
fi
|
||||
|
||||
unset SUMMARY_ONLY
|
||||
DIR="$1"
|
||||
if [ "$1" = "-d" ]; then
|
||||
PROCESS_DEAD=1
|
||||
fi
|
||||
|
||||
shift
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
DIR="$1"
|
||||
|
||||
if [ "$DIR" = "" ]; then
|
||||
|
||||
echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2
|
||||
echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
|
||||
echo 1>&2
|
||||
echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2
|
||||
echo "just the summary results. See docs/parallel_fuzzing.txt for additional tips." 1>&2
|
||||
echo Options: 1>&2
|
||||
echo " -s - skip details and output summary results only" 1>&2
|
||||
echo " -d - include dead fuzzer stats" 1>&2
|
||||
echo 1>&2
|
||||
exit 1
|
||||
|
||||
@ -52,9 +70,16 @@ if [ -d queue ]; then
|
||||
|
||||
fi
|
||||
|
||||
RED=`tput setaf 9 1 1`
|
||||
GREEN=`tput setaf 2 1 1`
|
||||
BLUE=`tput setaf 4 1 1`
|
||||
YELLOW=`tput setaf 11 1 1`
|
||||
NC=`tput sgr0`
|
||||
RESET="$NC"
|
||||
|
||||
CUR_TIME=`date +%s`
|
||||
|
||||
TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || exit 1
|
||||
TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1
|
||||
|
||||
ALIVE_CNT=0
|
||||
DEAD_CNT=0
|
||||
@ -66,6 +91,12 @@ TOTAL_CRASHES=0
|
||||
TOTAL_PFAV=0
|
||||
TOTAL_PENDING=0
|
||||
|
||||
# Time since last path / crash / hang, formatted as string
|
||||
FMT_TIME="0 days 0 hours"
|
||||
FMT_PATH="${RED}none seen yet${NC}"
|
||||
FMT_CRASH="none seen yet"
|
||||
FMT_HANG="none seen yet"
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
echo "Individual fuzzers"
|
||||
@ -74,18 +105,56 @@ if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
fi
|
||||
|
||||
fmt_duration()
|
||||
{
|
||||
DUR_STRING=
|
||||
if [ $1 -le 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local duration=$((CUR_TIME - $1))
|
||||
local days=$((duration / 60 / 60 / 24))
|
||||
local hours=$(((duration / 60 / 60) % 24))
|
||||
local minutes=$(((duration / 60) % 60))
|
||||
local seconds=$((duration % 60))
|
||||
|
||||
if [ $duration -le 0 ]; then
|
||||
DUR_STRING="0 seconds"
|
||||
elif [ $duration -eq 1 ]; then
|
||||
DUR_STRING="1 second"
|
||||
elif [ $days -gt 0 ]; then
|
||||
DUR_STRING="$days days, $hours hours"
|
||||
elif [ $hours -gt 0 ]; then
|
||||
DUR_STRING="$hours hours, $minutes minutes"
|
||||
elif [ $minutes -gt 0 ]; then
|
||||
DUR_STRING="$minutes minutes, $seconds seconds"
|
||||
else
|
||||
DUR_STRING="$seconds seconds"
|
||||
fi
|
||||
}
|
||||
|
||||
FIRST=true
|
||||
TOTAL_WCOP=
|
||||
TOTAL_LAST_PATH=0
|
||||
|
||||
for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
|
||||
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
|
||||
. "$TMP"
|
||||
|
||||
RUN_UNIX=$((CUR_TIME - start_time))
|
||||
RUN_UNIX=$run_time
|
||||
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
|
||||
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
|
||||
|
||||
test -n "$cycles_wo_finds" && {
|
||||
test -z "$FIRST" && TOTAL_WCOP="${TOTAL_WCOP}/"
|
||||
TOTAL_WCOP="${TOTAL_WCOP}${cycles_wo_finds}"
|
||||
FIRST=
|
||||
}
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) <<<"
|
||||
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
|
||||
echo
|
||||
|
||||
fi
|
||||
@ -100,13 +169,20 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
fi
|
||||
|
||||
DEAD_CNT=$((DEAD_CNT + 1))
|
||||
continue
|
||||
last_path=0
|
||||
|
||||
if [ "$PROCESS_DEAD" = "" ]; then
|
||||
|
||||
continue
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
ALIVE_CNT=$((ALIVE_CNT + 1))
|
||||
|
||||
EXEC_SEC=$((execs_done / RUN_UNIX))
|
||||
EXEC_SEC=0
|
||||
test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
|
||||
PATH_PERC=$((cur_path * 100 / paths_total))
|
||||
|
||||
TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
|
||||
@ -116,8 +192,43 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
|
||||
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
|
||||
|
||||
if [ "$last_path" -gt "$TOTAL_LAST_PATH" ]; then
|
||||
TOTAL_LAST_PATH=$last_path
|
||||
fi
|
||||
|
||||
if [ "$SUMMARY_ONLY" = "" ]; then
|
||||
|
||||
# Warnings in red
|
||||
TIMEOUT_PERC=$((exec_timeout * 100 / execs_done))
|
||||
if [ $TIMEOUT_PERC -ge 10 ]; then
|
||||
echo " ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
|
||||
fi
|
||||
|
||||
if [ $EXEC_SEC -eq 0 ]; then
|
||||
echo " ${YELLOW}no data yet, 0 execs/sec${NC}"
|
||||
elif [ $EXEC_SEC -lt 100 ]; then
|
||||
echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
|
||||
fi
|
||||
|
||||
fmt_duration $last_path && FMT_PATH=$DUR_STRING
|
||||
fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
|
||||
fmt_duration $last_hang && FMT_HANG=$DUR_STRING
|
||||
FMT_CWOP="not available"
|
||||
test -n "$cycles_wo_finds" && {
|
||||
test "$cycles_wo_finds" = 0 && FMT_CWOP="$cycles_wo_finds"
|
||||
test "$cycles_wo_finds" -gt 10 && FMT_CWOP="${YELLOW}$cycles_wo_finds${NC}"
|
||||
test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
|
||||
}
|
||||
|
||||
echo " last_path : $FMT_PATH"
|
||||
echo " last_crash : $FMT_CRASH"
|
||||
echo " last_hang : $FMT_HANG"
|
||||
echo " cycles_wo_finds : $FMT_CWOP"
|
||||
|
||||
CPU_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $3}')
|
||||
MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
|
||||
|
||||
echo " cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
|
||||
echo " cycle $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, path $cur_path/$paths_total (${PATH_PERC}%)"
|
||||
|
||||
if [ "$unique_crashes" = "0" ]; then
|
||||
@ -132,25 +243,56 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
|
||||
|
||||
done
|
||||
|
||||
# Formatting for total time, time since last path, crash, and hang
|
||||
fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
|
||||
# Formatting for total execution
|
||||
FMT_EXECS="0 millions"
|
||||
EXECS_MILLION=$((TOTAL_EXECS / 1000 / 1000))
|
||||
EXECS_THOUSAND=$((TOTAL_EXECS / 1000 % 1000))
|
||||
if [ $EXECS_MILLION -gt 9 ]; then
|
||||
FMT_EXECS="$EXECS_MILLION millions"
|
||||
elif [ $EXECS_MILLION -gt 0 ]; then
|
||||
FMT_EXECS="$EXECS_MILLION millions, $EXECS_THOUSAND thousands"
|
||||
else
|
||||
FMT_EXECS="$EXECS_THOUSAND thousands"
|
||||
fi
|
||||
|
||||
rm -f "$TMP"
|
||||
|
||||
TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
|
||||
TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
|
||||
|
||||
test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
|
||||
fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
|
||||
|
||||
test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
|
||||
|
||||
if [ "$PROCESS_DEAD" = "" ]; then
|
||||
|
||||
TXT="excluded from stats"
|
||||
|
||||
else
|
||||
|
||||
TXT="included in stats"
|
||||
ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
|
||||
|
||||
fi
|
||||
|
||||
echo "Summary stats"
|
||||
echo "============="
|
||||
echo
|
||||
echo " Fuzzers alive : $ALIVE_CNT"
|
||||
|
||||
if [ ! "$DEAD_CNT" = "0" ]; then
|
||||
echo " Dead or remote : $DEAD_CNT (excluded from stats)"
|
||||
echo " Dead or remote : $DEAD_CNT ($TXT)"
|
||||
fi
|
||||
|
||||
echo " Total run time : $TOTAL_DAYS days, $TOTAL_HRS hours"
|
||||
echo " Total execs : $((TOTAL_EXECS / 1000 / 1000)) million"
|
||||
echo " Total run time : $FMT_TIME"
|
||||
echo " Total execs : $FMT_EXECS"
|
||||
echo " Cumulative speed : $TOTAL_EPS execs/sec"
|
||||
if [ "$ALIVE_CNT" -gt "0" ]; then
|
||||
echo " Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
|
||||
fi
|
||||
echo " Pending paths : $TOTAL_PFAV faves, $TOTAL_PENDING total"
|
||||
|
||||
if [ "$ALIVE_CNT" -gt "1" ]; then
|
||||
@ -158,6 +300,8 @@ if [ "$ALIVE_CNT" -gt "1" ]; then
|
||||
fi
|
||||
|
||||
echo " Crashes found : $TOTAL_CRASHES locally unique"
|
||||
echo "Cycles without finds : $TOTAL_WCOP"
|
||||
echo " Time without finds : $TOTAL_LAST_PATH"
|
||||
echo
|
||||
|
||||
exit 0
|
||||
|
80
afl-wine-trace
Executable file
80
afl-wine-trace
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pefile
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("[afl-wine-trace] usage: ./afl-wine-trace binary [args...]\n")
|
||||
exit(1)
|
||||
|
||||
if os.getenv("AFL_PATH"):
|
||||
my_dir = os.getenv("AFL_PATH")
|
||||
else:
|
||||
my_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
os.environ["WINELOADERNOEXEC"] = "1"
|
||||
|
||||
pe = pefile.PE(sys.argv[1])
|
||||
|
||||
if "AFL_ENTRYPOINT" not in os.environ:
|
||||
os.environ["AFL_ENTRYPOINT"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint)
|
||||
if not os.getenv("AFL_INST_LIBS"):
|
||||
if "AFL_CODE_START" not in os.environ:
|
||||
os.environ["AFL_CODE_START"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode)
|
||||
if "AFL_CODE_END" not in os.environ:
|
||||
os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
|
||||
|
||||
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64"
|
||||
else:
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32"
|
||||
|
||||
if os.getenv("WINECOV_QEMU_PATH"):
|
||||
qemu_path = os.getenv("WINECOV_QEMU_PATH")
|
||||
elif os.path.exists(os.path.join(my_dir, "afl-qemu-trace")):
|
||||
qemu_path = os.path.join(my_dir, "afl-qemu-trace")
|
||||
else:
|
||||
qemu_path = "qemu-"
|
||||
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
|
||||
qemu_path += "x86_64"
|
||||
elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
|
||||
qemu_path += "i386"
|
||||
else:
|
||||
print ("[afl-wine-trace] unsuppoted architecture\n")
|
||||
exit(1)
|
||||
qemu_path = shutil.which(qemu_path)
|
||||
|
||||
wine_path = None
|
||||
if os.getenv("AFL_WINE_PATH"):
|
||||
wine_path = os.getenv("AFL_WINE_PATH")
|
||||
else:
|
||||
if not wine_path and shutil.which("wine"):
|
||||
wine_path = shutil.which("wine")
|
||||
if not wine_path and os.path.exists("/usr/bin/wine"):
|
||||
wine_path = "/usr/bin/wine"
|
||||
if not wine_path and os.path.exists("/usr/lib/wine/wine"):
|
||||
wine_path = "/usr/lib/wine/wine"
|
||||
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
|
||||
wine_path += "64"
|
||||
elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
|
||||
pass
|
||||
else:
|
||||
print ("[afl-wine-trace] unsopported architecture\n")
|
||||
exit(1)
|
||||
|
||||
argv = sys.argv[1:]
|
||||
for i in range(len(argv)):
|
||||
if ".cur_input" in argv[i]:
|
||||
# Get the Wine translated path using the winepath tool
|
||||
arg_translated = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
|
||||
# Remove the spurious LF at the end of the path
|
||||
if len(arg_translated) > 0 and arg_translated[-1] == '\n':
|
||||
arg_translated = arg_translated[:-1]
|
||||
argv[i] = arg_translated
|
||||
break
|
||||
|
||||
print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))
|
||||
os.execve(qemu_path, [qemu_path, wine_path] + argv, os.environ)
|
570
alloc-inl.h
570
alloc-inl.h
@ -1,570 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop - error-checking, memory-zeroing alloc routines
|
||||
------------------------------------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
|
||||
Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This allocator is not designed to resist malicious attackers (the canaries
|
||||
are small and predictable), but provides a robust and portable way to detect
|
||||
use-after-free, off-by-one writes, stale pointers, and so on.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_ALLOC_INL_H
|
||||
#define _HAVE_ALLOC_INL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
#define alloc_printf(_str...) ({ \
|
||||
u8* _tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char*)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
})
|
||||
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
|
||||
#define ALLOC_CHECK_SIZE(_s) do { \
|
||||
if ((_s) > MAX_ALLOC) \
|
||||
ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
} while (0)
|
||||
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) do { \
|
||||
if (!(_r)) \
|
||||
ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
} while (0)
|
||||
|
||||
/* Magic tokens used to mark used / freed chunks. */
|
||||
|
||||
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
|
||||
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
|
||||
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
|
||||
|
||||
/* Positions of guard tokens in relation to the user-visible pointer. */
|
||||
|
||||
#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
|
||||
#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
|
||||
#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
|
||||
|
||||
#define ALLOC_OFF_HEAD 8
|
||||
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
|
||||
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
|
||||
#define ALLOC_BLK_INC 256
|
||||
|
||||
/* Sanity-checking macros for pointers. */
|
||||
|
||||
#define CHECK_PTR(_p) do { \
|
||||
if (_p) { \
|
||||
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
|
||||
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
|
||||
ABORT("Use after free."); \
|
||||
else ABORT("Corrupted head alloc canary."); \
|
||||
} \
|
||||
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
|
||||
ABORT("Corrupted tail alloc canary."); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PTR_EXPR(_p) ({ \
|
||||
typeof (_p) _tmp = (_p); \
|
||||
CHECK_PTR(_tmp); \
|
||||
_tmp; \
|
||||
})
|
||||
|
||||
|
||||
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
|
||||
requests. */
|
||||
|
||||
static inline void* DFL_ck_alloc_nozero(u32 size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (!size) return NULL;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Allocate a buffer, returning zeroed memory. */
|
||||
|
||||
static inline void* DFL_ck_alloc(u32 size) {
|
||||
|
||||
void* mem;
|
||||
|
||||
if (!size) return NULL;
|
||||
mem = DFL_ck_alloc_nozero(size);
|
||||
|
||||
return memset(mem, 0, size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
||||
is set, the old memory will be also clobbered with 0xFF. */
|
||||
|
||||
static inline void DFL_ck_free(void* mem) {
|
||||
|
||||
if (!mem) return;
|
||||
|
||||
CHECK_PTR(mem);
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
|
||||
/* Catch pointer issues sooner. */
|
||||
memset(mem, 0xFF, ALLOC_S(mem));
|
||||
|
||||
#endif /* DEBUG_BUILD */
|
||||
|
||||
ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
||||
|
||||
free(mem - ALLOC_OFF_HEAD);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
|
||||
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
|
||||
old memory is clobbered with 0xFF. */
|
||||
|
||||
static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
void* ret;
|
||||
u32 old_size = 0;
|
||||
|
||||
if (!size) {
|
||||
|
||||
DFL_ck_free(orig);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if (orig) {
|
||||
|
||||
CHECK_PTR(orig);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
ALLOC_C1(orig) = ALLOC_MAGIC_F;
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
old_size = ALLOC_S(orig);
|
||||
orig -= ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_CHECK_SIZE(old_size);
|
||||
|
||||
}
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
#else
|
||||
|
||||
/* Catch pointer issues sooner: force relocation and make sure that the
|
||||
original buffer is wiped. */
|
||||
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
if (orig) {
|
||||
|
||||
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
|
||||
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
||||
|
||||
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
|
||||
|
||||
free(orig);
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
if (size > old_size)
|
||||
memset(ret + old_size, 0, size - old_size);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
|
||||
repeated small reallocs without complicating the user code). */
|
||||
|
||||
static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
if (orig) {
|
||||
|
||||
CHECK_PTR(orig);
|
||||
|
||||
if (ALLOC_S(orig) >= size) return orig;
|
||||
|
||||
size += ALLOC_BLK_INC;
|
||||
|
||||
}
|
||||
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
return DFL_ck_realloc(orig, size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_strdup(u8* str) {
|
||||
|
||||
void* ret;
|
||||
u32 size;
|
||||
|
||||
if (!str) return NULL;
|
||||
|
||||
size = strlen((char*)str) + 1;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
return memcpy(ret, str, size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
||||
or NULL inputs. */
|
||||
|
||||
static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
return memcpy(ret, mem, size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
||||
Returns NULL for zero-sized or NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
|
||||
u8* ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL + 1);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
||||
ALLOC_S(ret) = size;
|
||||
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
||||
|
||||
memcpy(ret, mem, size);
|
||||
ret[size] = 0;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above functions
|
||||
to user-visible names such as ck_alloc(). */
|
||||
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
|
||||
#else
|
||||
|
||||
/* In debugging mode, we also track allocations to detect memory leaks, and the
|
||||
flow goes through one more layer of indirection. */
|
||||
|
||||
/* Alloc tracking data structures: */
|
||||
|
||||
#define ALLOC_BUCKETS 4096
|
||||
|
||||
struct TRK_obj {
|
||||
void *ptr;
|
||||
char *file, *func;
|
||||
u32 line;
|
||||
};
|
||||
|
||||
#ifdef AFL_MAIN
|
||||
|
||||
struct TRK_obj* TRK[ALLOC_BUCKETS];
|
||||
u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
# define alloc_report() TRK_report()
|
||||
|
||||
#else
|
||||
|
||||
extern struct TRK_obj* TRK[ALLOC_BUCKETS];
|
||||
extern u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
# define alloc_report()
|
||||
|
||||
#endif /* ^AFL_MAIN */
|
||||
|
||||
/* Bucket-assigning function for a given pointer: */
|
||||
|
||||
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
|
||||
|
||||
|
||||
/* Add a new entry to the list of allocated objects. */
|
||||
|
||||
static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
if (!ptr) return;
|
||||
|
||||
bucket = TRKH(ptr);
|
||||
|
||||
/* Find a free slot in the list of entries for that bucket. */
|
||||
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
|
||||
if (!TRK[bucket][i].ptr) {
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char*)file;
|
||||
TRK[bucket][i].func = (char*)func;
|
||||
TRK[bucket][i].line = line;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* No space available - allocate more. */
|
||||
|
||||
TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
|
||||
(TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char*)file;
|
||||
TRK[bucket][i].func = (char*)func;
|
||||
TRK[bucket][i].line = line;
|
||||
|
||||
TRK_cnt[bucket]++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Remove entry from the list of allocated objects. */
|
||||
|
||||
static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
if (!ptr) return;
|
||||
|
||||
bucket = TRKH(ptr);
|
||||
|
||||
/* Find the element on the list... */
|
||||
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
|
||||
if (TRK[bucket][i].ptr == ptr) {
|
||||
|
||||
TRK[bucket][i].ptr = 0;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
|
||||
func, file, line);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Do a final report on all non-deallocated objects. */
|
||||
|
||||
static inline void TRK_report(void) {
|
||||
|
||||
u32 i, bucket;
|
||||
|
||||
fflush(0);
|
||||
|
||||
for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
|
||||
for (i = 0; i < TRK_cnt[bucket]; i++)
|
||||
if (TRK[bucket][i].ptr)
|
||||
WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
|
||||
TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Simple wrappers for non-debugging functions: */
|
||||
|
||||
static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
|
||||
u32 line) {
|
||||
|
||||
void* ret = DFL_ck_alloc(size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_realloc(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_realloc_block(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
|
||||
u32 line) {
|
||||
|
||||
void* ret = DFL_ck_strdup(str);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_memdup(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_memdup_str(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void TRK_ck_free(void* ptr, const char* file,
|
||||
const char* func, u32 line) {
|
||||
|
||||
TRK_free_buf(ptr, file, func, line);
|
||||
DFL_ck_free(ptr);
|
||||
|
||||
}
|
||||
|
||||
/* Aliasing user-facing names to tracking functions: */
|
||||
|
||||
#define ck_alloc(_p1) \
|
||||
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_alloc_nozero(_p1) \
|
||||
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc(_p1, _p2) \
|
||||
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc_block(_p1, _p2) \
|
||||
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_strdup(_p1) \
|
||||
TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup(_p1, _p2) \
|
||||
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup_str(_p1, _p2) \
|
||||
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_free(_p1) \
|
||||
TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
#endif /* ! _HAVE_ALLOC_INL_H */
|
354
config.h
354
config.h
@ -1,354 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop plus plus - vaguely configurable bits
|
||||
----------------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
|
||||
Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CONFIG_H
|
||||
#define _HAVE_CONFIG_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* Version string: */
|
||||
|
||||
#define VERSION "++2.52c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
* Settings that may be of interest to power users: *
|
||||
* *
|
||||
******************************************************/
|
||||
|
||||
/* Comment out to disable terminal colors (note that this makes afl-analyze
|
||||
a lot less nice): */
|
||||
|
||||
#define USE_COLOR
|
||||
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
#define FANCY_BOXES
|
||||
|
||||
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||
also used for detecting hangs; the actual value is auto-scaled: */
|
||||
|
||||
#define EXEC_TIMEOUT 1000
|
||||
|
||||
/* Timeout rounding factor when auto-scaling (milliseconds): */
|
||||
|
||||
#define EXEC_TM_ROUND 20
|
||||
|
||||
/* Default memory limit for child process (MB): */
|
||||
|
||||
#ifndef __x86_64__
|
||||
# define MEM_LIMIT 25
|
||||
#else
|
||||
# define MEM_LIMIT 50
|
||||
#endif /* ^!__x86_64__ */
|
||||
|
||||
/* Default memory limit when running in QEMU mode (MB): */
|
||||
|
||||
#define MEM_LIMIT_QEMU 200
|
||||
|
||||
/* Number of calibration cycles per every new test case (and for test
|
||||
cases that show variable behavior): */
|
||||
|
||||
#define CAL_CYCLES 8
|
||||
#define CAL_CYCLES_LONG 40
|
||||
|
||||
/* Number of subsequent timeouts before abandoning an input file: */
|
||||
|
||||
#define TMOUT_LIMIT 250
|
||||
|
||||
/* Maximum number of unique hangs or crashes to record: */
|
||||
|
||||
#define KEEP_UNIQUE_HANG 500
|
||||
#define KEEP_UNIQUE_CRASH 5000
|
||||
|
||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||
|
||||
#define HAVOC_CYCLES 256
|
||||
#define HAVOC_CYCLES_INIT 1024
|
||||
|
||||
/* Maximum multiplier for the above (should be a power of two, beware
|
||||
of 32-bit int overflows): */
|
||||
|
||||
#define HAVOC_MAX_MULT 16
|
||||
|
||||
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
||||
|
||||
#define HAVOC_MIN 16
|
||||
|
||||
/* Power Schedule Divisor */
|
||||
#define POWER_BETA 1
|
||||
#define MAX_FACTOR (POWER_BETA * 32)
|
||||
|
||||
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
|
||||
like this:
|
||||
|
||||
n = random between 1 and HAVOC_STACK_POW2
|
||||
stacking = 2^n
|
||||
|
||||
In other words, the default (n = 7) produces 2, 4, 8, 16, 32, 64, or
|
||||
128 stacked tweaks: */
|
||||
|
||||
#define HAVOC_STACK_POW2 7
|
||||
|
||||
/* Caps on block sizes for cloning and deletion operations. Each of these
|
||||
ranges has a 33% probability of getting picked, except for the first
|
||||
two cycles where smaller blocks are favored: */
|
||||
|
||||
#define HAVOC_BLK_SMALL 32
|
||||
#define HAVOC_BLK_MEDIUM 128
|
||||
#define HAVOC_BLK_LARGE 1500
|
||||
|
||||
/* Extra-large blocks, selected very rarely (<5% of the time): */
|
||||
|
||||
#define HAVOC_BLK_XL 32768
|
||||
|
||||
/* Probabilities of skipping non-favored entries in the queue, expressed as
|
||||
percentages: */
|
||||
|
||||
#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */
|
||||
#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */
|
||||
#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
|
||||
|
||||
/* Splicing cycle count: */
|
||||
|
||||
#define SPLICE_CYCLES 15
|
||||
|
||||
/* Nominal per-splice havoc cycle length: */
|
||||
|
||||
#define SPLICE_HAVOC 32
|
||||
|
||||
/* Maximum offset for integer addition / subtraction stages: */
|
||||
|
||||
#define ARITH_MAX 35
|
||||
|
||||
/* Limits for the test case trimmer. The absolute minimum chunk size; and
|
||||
the starting and ending divisors for chopping up the input file: */
|
||||
|
||||
#define TRIM_MIN_BYTES 4
|
||||
#define TRIM_START_STEPS 16
|
||||
#define TRIM_END_STEPS 1024
|
||||
|
||||
/* Maximum size of input file, in bytes (keep under 100MB): */
|
||||
|
||||
#define MAX_FILE (1 * 1024 * 1024)
|
||||
|
||||
/* The same, for the test case minimizer: */
|
||||
|
||||
#define TMIN_MAX_FILE (10 * 1024 * 1024)
|
||||
|
||||
/* Block normalization steps for afl-tmin: */
|
||||
|
||||
#define TMIN_SET_MIN_SIZE 4
|
||||
#define TMIN_SET_STEPS 128
|
||||
|
||||
/* Maximum dictionary token size (-x), in bytes: */
|
||||
|
||||
#define MAX_DICT_FILE 128
|
||||
|
||||
/* Length limits for auto-detected dictionary tokens: */
|
||||
|
||||
#define MIN_AUTO_EXTRA 3
|
||||
#define MAX_AUTO_EXTRA 32
|
||||
|
||||
/* Maximum number of user-specified dictionary tokens to use in deterministic
|
||||
steps; past this point, the "extras/user" step will be still carried out,
|
||||
but with proportionally lower odds: */
|
||||
|
||||
#define MAX_DET_EXTRAS 200
|
||||
|
||||
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
|
||||
(first value), and to keep in memory as candidates. The latter should be much
|
||||
higher than the former. */
|
||||
|
||||
#define USE_AUTO_EXTRAS 50
|
||||
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
|
||||
|
||||
/* Scaling factor for the effector map used to skip some of the more
|
||||
expensive deterministic steps. The actual divisor is set to
|
||||
2^EFF_MAP_SCALE2 bytes: */
|
||||
|
||||
#define EFF_MAP_SCALE2 3
|
||||
|
||||
/* Minimum input file length at which the effector logic kicks in: */
|
||||
|
||||
#define EFF_MIN_LEN 128
|
||||
|
||||
/* Maximum effector density past which everything is just fuzzed
|
||||
unconditionally (%): */
|
||||
|
||||
#define EFF_MAX_PERC 90
|
||||
|
||||
/* UI refresh frequency (Hz): */
|
||||
|
||||
#define UI_TARGET_HZ 5
|
||||
|
||||
/* Fuzzer stats file and plot update intervals (sec): */
|
||||
|
||||
#define STATS_UPDATE_SEC 60
|
||||
#define PLOT_UPDATE_SEC 5
|
||||
|
||||
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 5
|
||||
|
||||
/* Output directory reuse grace period (minutes): */
|
||||
|
||||
#define OUTPUT_GRACE 25
|
||||
|
||||
/* Uncomment to use simple file names (id_NNNNNN): */
|
||||
|
||||
// #define SIMPLE_FILES
|
||||
|
||||
/* List of interesting values to use in fuzzing. */
|
||||
|
||||
#define INTERESTING_8 \
|
||||
-128, /* Overflow signed 8-bit when decremented */ \
|
||||
-1, /* */ \
|
||||
0, /* */ \
|
||||
1, /* */ \
|
||||
16, /* One-off with common buffer size */ \
|
||||
32, /* One-off with common buffer size */ \
|
||||
64, /* One-off with common buffer size */ \
|
||||
100, /* One-off with common buffer size */ \
|
||||
127 /* Overflow signed 8-bit when incremented */
|
||||
|
||||
#define INTERESTING_16 \
|
||||
-32768, /* Overflow signed 16-bit when decremented */ \
|
||||
-129, /* Overflow signed 8-bit */ \
|
||||
128, /* Overflow signed 8-bit */ \
|
||||
255, /* Overflow unsig 8-bit when incremented */ \
|
||||
256, /* Overflow unsig 8-bit */ \
|
||||
512, /* One-off with common buffer size */ \
|
||||
1000, /* One-off with common buffer size */ \
|
||||
1024, /* One-off with common buffer size */ \
|
||||
4096, /* One-off with common buffer size */ \
|
||||
32767 /* Overflow signed 16-bit when incremented */
|
||||
|
||||
#define INTERESTING_32 \
|
||||
-2147483648LL, /* Overflow signed 32-bit when decremented */ \
|
||||
-100663046, /* Large negative number (endian-agnostic) */ \
|
||||
-32769, /* Overflow signed 16-bit */ \
|
||||
32768, /* Overflow signed 16-bit */ \
|
||||
65535, /* Overflow unsig 16-bit when incremented */ \
|
||||
65536, /* Overflow unsig 16 bit */ \
|
||||
100663045, /* Large positive number (endian-agnostic) */ \
|
||||
2147483647 /* Overflow signed 32-bit when incremented */
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Really exotic stuff you probably don't want to touch: *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
|
||||
|
||||
#define RESEED_RNG 10000
|
||||
|
||||
/* Maximum line length passed from GCC to 'as' and used for parsing
|
||||
configuration files: */
|
||||
|
||||
#define MAX_LINE 8192
|
||||
|
||||
/* Environment variable used to pass SHM ID to the called program. */
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
#define CLANG_ENV_VAR "__AFL_CLANG_MODE"
|
||||
#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
|
||||
#define PERSIST_ENV_VAR "__AFL_PERSISTENT"
|
||||
#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
|
||||
|
||||
/* In-code signatures for deferred and persistent mode. */
|
||||
|
||||
#define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
|
||||
#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
|
||||
|
||||
/* Distinctive bitmap signature used to indicate failed execution: */
|
||||
|
||||
#define EXEC_FAIL_SIG 0xfee1dead
|
||||
|
||||
/* Distinctive exit code used to indicate MSAN trip condition: */
|
||||
|
||||
#define MSAN_ERROR 86
|
||||
|
||||
/* Designated file descriptors for forkserver commands (the application will
|
||||
use FORKSRV_FD and FORKSRV_FD + 1): */
|
||||
|
||||
#define FORKSRV_FD 198
|
||||
|
||||
/* Fork server init timeout multiplier: we'll wait the user-selected
|
||||
timeout plus this much for the fork server to spin up. */
|
||||
|
||||
#define FORK_WAIT_MULT 10
|
||||
|
||||
/* Calibration timeout adjustments, to be a bit more generous when resuming
|
||||
fuzzing sessions or trying to calibrate already-added internal finds.
|
||||
The first value is a percentage, the other is in milliseconds: */
|
||||
|
||||
#define CAL_TMOUT_PERC 125
|
||||
#define CAL_TMOUT_ADD 50
|
||||
|
||||
/* Number of chances to calibrate a case before giving up: */
|
||||
|
||||
#define CAL_CHANCES 3
|
||||
|
||||
/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than
|
||||
2; you probably want to keep it under 18 or so for performance reasons
|
||||
(adjusting AFL_INST_RATIO when compiling is probably a better way to solve
|
||||
problems with complex programs). You need to recompile the target binary
|
||||
after changing this - otherwise, SEGVs may ensue. */
|
||||
|
||||
#define MAP_SIZE_POW2 16
|
||||
#define MAP_SIZE (1 << MAP_SIZE_POW2)
|
||||
|
||||
/* Maximum allocator request size (keep well under INT_MAX): */
|
||||
|
||||
#define MAX_ALLOC 0x40000000
|
||||
|
||||
/* A made-up hashing seed: */
|
||||
|
||||
#define HASH_CONST 0xa5b35705
|
||||
|
||||
/* Constants for afl-gotcpu to control busy loop timing: */
|
||||
|
||||
#define CTEST_TARGET_MS 5000
|
||||
#define CTEST_CORE_TRG_MS 1000
|
||||
#define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
|
||||
|
||||
/* Uncomment this to use inferior block-coverage-based instrumentation. Note
|
||||
that you need to recompile the target binary for this to have any effect: */
|
||||
|
||||
// #define COVERAGE_ONLY
|
||||
|
||||
/* Uncomment this to ignore hit counts and output just one bit per tuple.
|
||||
As with the previous setting, you will need to recompile the target
|
||||
binary: */
|
||||
|
||||
// #define SKIP_COUNTS
|
||||
|
||||
/* Uncomment this to use instrumentation data to record newly discovered paths,
|
||||
but do not use them as seeds for fuzzing. This is useful for conveniently
|
||||
measuring coverage that could be attained by a "dumb" fuzzing algorithm: */
|
||||
|
||||
// #define IGNORE_FINDS
|
||||
|
||||
#endif /* ! _HAVE_CONFIG_H */
|
121
custom_mutators/Android.bp
Normal file
121
custom_mutators/Android.bp
Normal file
@ -0,0 +1,121 @@
|
||||
cc_library_shared {
|
||||
name: "libfuzzer-mutator",
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
|
||||
cflags: [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-funroll-loops",
|
||||
"-fPIC",
|
||||
"-fpermissive",
|
||||
"-std=c++11",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-variable",
|
||||
],
|
||||
|
||||
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",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-function",
|
||||
],
|
||||
|
||||
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",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-pointer-sign",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"symcc/symcc.c",
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libafl_headers",
|
||||
],
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"libprotobuf-mutator-example",
|
||||
]
|
59
custom_mutators/README.md
Normal file
59
custom_mutators/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Custom Mutators
|
||||
|
||||
Custom mutators enhance and alter the mutation strategies of afl++.
|
||||
For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
|
||||
|
||||
## Examples
|
||||
|
||||
The `./examples` folder contains examples for custom mutators in python and C.
|
||||
|
||||
## Rust
|
||||
|
||||
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
|
||||
|
||||
## The afl++ Grammar Mutator
|
||||
|
||||
If you use git to clone afl++, then the following will incorporate our
|
||||
excellent grammar custom mutator:
|
||||
```sh
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
Read the README in the [Grammar-Mutator] repository on how to use it.
|
||||
|
||||
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
|
||||
|
||||
## Production-Ready Custom Mutators
|
||||
|
||||
This directory holds ready to use custom mutators.
|
||||
Just type "make" in the individual subdirectories.
|
||||
|
||||
Use with e.g.
|
||||
|
||||
`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....`
|
||||
|
||||
and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
|
||||
|
||||
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
|
||||
|
||||
## 3rd Party Custom Mutators
|
||||
|
||||
### Superion Mutators
|
||||
|
||||
Adrian Tiron ported the Superion grammar fuzzer to afl++, it is WIP and
|
||||
requires cmake (among other things):
|
||||
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
|
||||
|
||||
### libprotobuf Mutators
|
||||
|
||||
There are two WIP protobuf projects, that require work to be working though:
|
||||
|
||||
transforms protobuf raw:
|
||||
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
|
||||
|
||||
has a transform function you need to fill for your protobuf format, however
|
||||
needs to be ported to the updated afl++ custom mutator API (not much work):
|
||||
https://github.com/thebabush/afl-libprotobuf-mutator
|
||||
|
||||
same as above but is for current afl++:
|
||||
https://github.com/P1umer/AFLplusplus-protobuf-mutator
|
7
custom_mutators/examples/Makefile
Normal file
7
custom_mutators/examples/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: libexamplemutator.so
|
||||
|
||||
libexamplemutator.so:
|
||||
$(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so
|
||||
|
||||
clean:
|
||||
rm -rf libexamplemutator.so
|
35
custom_mutators/examples/README.md
Normal file
35
custom_mutators/examples/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Examples for the custom mutator
|
||||
|
||||
These are example and helper files for the custom mutator feature.
|
||||
See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use python2.7 to compile python2 scripts!
|
||||
|
||||
simple_example.c - most simplest example. generates a random sized buffer
|
||||
filled with 'A'
|
||||
|
||||
example.c - this is a simple example written in C and should be compiled to a
|
||||
shared library. Use make to compile it and produce libexamplemutator.so
|
||||
|
||||
example.py - this is the template you can use, the functions are there but they
|
||||
are empty
|
||||
|
||||
post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF
|
||||
|
||||
post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
||||
|
||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||
|
||||
XmlMutatorMin.py - module for XML mutation
|
||||
|
||||
custom_mutator_helpers.h is an header that defines some helper routines
|
||||
like surgical_havoc_mutate() that allow to perform a randomly chosen
|
||||
mutation from a subset of the havoc mutations.
|
||||
If you do so, you have to specify -I /path/to/AFLplusplus/include when
|
||||
compiling.
|
348
custom_mutators/examples/XmlMutatorMin.py
Normal file
348
custom_mutators/examples/XmlMutatorMin.py
Normal file
@ -0,0 +1,348 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """
|
||||
|
||||
from __future__ import print_function
|
||||
from copy import deepcopy
|
||||
from lxml import etree as ET
|
||||
import random, re, io
|
||||
|
||||
|
||||
###########################
|
||||
# The XmlMutatorMin class #
|
||||
###########################
|
||||
|
||||
|
||||
class XmlMutatorMin:
|
||||
|
||||
"""
|
||||
Optionals parameters:
|
||||
seed Seed used by the PRNG (default: "RANDOM")
|
||||
verbose Verbosity (default: False)
|
||||
"""
|
||||
|
||||
def __init__(self, seed="RANDOM", verbose=False):
|
||||
|
||||
""" Initialize seed, database and mutators """
|
||||
|
||||
# Verbosity
|
||||
self.verbose = verbose
|
||||
|
||||
# Initialize PRNG
|
||||
self.seed = str(seed)
|
||||
if self.seed == "RANDOM":
|
||||
random.seed()
|
||||
else:
|
||||
if self.verbose:
|
||||
print("Static seed '%s'" % self.seed)
|
||||
random.seed(self.seed)
|
||||
|
||||
# Initialize input and output documents
|
||||
self.input_tree = None
|
||||
self.tree = None
|
||||
|
||||
# High-level mutators (no database needed)
|
||||
hl_mutators_delete = [
|
||||
"del_node_and_children",
|
||||
"del_node_but_children",
|
||||
"del_attribute",
|
||||
"del_content",
|
||||
] # Delete items
|
||||
hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values
|
||||
|
||||
# Exposed mutators
|
||||
self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete
|
||||
|
||||
def __parse_xml(self, xml):
|
||||
|
||||
""" Parse an XML string. Basic wrapper around lxml.parse() """
|
||||
|
||||
try:
|
||||
# Function parse() takes care of comments / DTD / processing instructions / ...
|
||||
tree = ET.parse(io.BytesIO(xml))
|
||||
except ET.ParseError:
|
||||
raise RuntimeError("XML isn't well-formed!")
|
||||
except LookupError as e:
|
||||
raise RuntimeError(e)
|
||||
|
||||
# Return a document wrapper
|
||||
return tree
|
||||
|
||||
def __exec_among(self, module, functions, min_times, max_times):
|
||||
|
||||
""" Randomly execute $functions between $min and $max times """
|
||||
|
||||
for i in xrange(random.randint(min_times, max_times)):
|
||||
# Function names are mangled because they are "private"
|
||||
getattr(module, "_XmlMutatorMin__" + random.choice(functions))()
|
||||
|
||||
def __serialize_xml(self, tree):
|
||||
|
||||
""" Serialize a XML document. Basic wrapper around lxml.tostring() """
|
||||
|
||||
return ET.tostring(
|
||||
tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding
|
||||
)
|
||||
|
||||
def __ver(self, version):
|
||||
|
||||
""" Helper for displaying lxml version numbers """
|
||||
|
||||
return ".".join(map(str, version))
|
||||
|
||||
def reset(self):
|
||||
|
||||
""" Reset the mutator """
|
||||
|
||||
self.tree = deepcopy(self.input_tree)
|
||||
|
||||
def init_from_string(self, input_string):
|
||||
|
||||
""" Initialize the mutator from a XML string """
|
||||
|
||||
# Get a pointer to the top-element
|
||||
self.input_tree = self.__parse_xml(input_string)
|
||||
|
||||
# Get a working copy
|
||||
self.tree = deepcopy(self.input_tree)
|
||||
|
||||
def save_to_string(self):
|
||||
|
||||
""" Return the current XML document as UTF-8 string """
|
||||
|
||||
# Return a text version of the tree
|
||||
return self.__serialize_xml(self.tree)
|
||||
|
||||
def __pick_element(self, exclude_root_node=False):
|
||||
|
||||
""" Pick a random element from the current document """
|
||||
|
||||
# Get a list of all elements, but nodes like PI and comments
|
||||
elems = list(self.tree.getroot().iter(tag=ET.Element))
|
||||
|
||||
# Is the root node excluded?
|
||||
if exclude_root_node:
|
||||
start = 1
|
||||
else:
|
||||
start = 0
|
||||
|
||||
# Pick a random element
|
||||
try:
|
||||
elem_id = random.randint(start, len(elems) - 1)
|
||||
elem = elems[elem_id]
|
||||
except ValueError:
|
||||
# Should only occurs if "exclude_root_node = True"
|
||||
return (None, None)
|
||||
|
||||
return (elem_id, elem)
|
||||
|
||||
def __fuzz_attribute(self):
|
||||
|
||||
""" Fuzz (part of) an attribute value """
|
||||
|
||||
# Select a node to modify
|
||||
(rand_elem_id, rand_elem) = self.__pick_element()
|
||||
|
||||
# Get all the attributes
|
||||
attribs = rand_elem.keys()
|
||||
|
||||
# Is there attributes?
|
||||
if len(attribs) < 1:
|
||||
if self.verbose:
|
||||
print("No attribute: can't replace!")
|
||||
return
|
||||
|
||||
# Pick a random attribute
|
||||
rand_attrib_id = random.randint(0, len(attribs) - 1)
|
||||
rand_attrib = attribs[rand_attrib_id]
|
||||
|
||||
# We have the attribute to modify
|
||||
# Get its value
|
||||
attrib_value = rand_elem.get(rand_attrib)
|
||||
# print("- Value: " + attrib_value)
|
||||
|
||||
# Should we work on the whole value?
|
||||
func_call = "(?P<func>[a-zA-Z:\-]+)\((?P<args>.*?)\)"
|
||||
p = re.compile(func_call)
|
||||
l = p.findall(attrib_value)
|
||||
if random.choice((True, False)) and l:
|
||||
# Randomly pick one the function calls
|
||||
(func, args) = random.choice(l)
|
||||
# Split by "," and randomly pick one of the arguments
|
||||
value = random.choice(args.split(","))
|
||||
# Remove superfluous characters
|
||||
unclean_value = value
|
||||
value = value.strip(" ").strip("'")
|
||||
# print("Selected argument: [%s]" % value)
|
||||
else:
|
||||
value = attrib_value
|
||||
|
||||
# For each type, define some possible replacement values
|
||||
choices_number = (
|
||||
"0",
|
||||
"11111",
|
||||
"-128",
|
||||
"2",
|
||||
"-1",
|
||||
"1/3",
|
||||
"42/0",
|
||||
"1094861636 idiv 1.0",
|
||||
"-1123329771506872 idiv 3.8",
|
||||
"17=$numericRTF",
|
||||
str(3 + random.randrange(0, 100)),
|
||||
)
|
||||
|
||||
choices_letter = (
|
||||
"P" * (25 * random.randrange(1, 100)),
|
||||
"%s%s%s%s%s%s",
|
||||
"foobar",
|
||||
)
|
||||
|
||||
choices_alnum = (
|
||||
"Abc123",
|
||||
"020F0302020204030204",
|
||||
"020F0302020204030204" * (random.randrange(5, 20)),
|
||||
)
|
||||
|
||||
# Fuzz the value
|
||||
if random.choice((True, False)) and value == "":
|
||||
|
||||
# Empty
|
||||
new_value = value
|
||||
|
||||
elif random.choice((True, False)) and value.isdigit():
|
||||
|
||||
# Numbers
|
||||
new_value = random.choice(choices_number)
|
||||
|
||||
elif random.choice((True, False)) and value.isalpha():
|
||||
|
||||
# Letters
|
||||
new_value = random.choice(choices_letter)
|
||||
|
||||
elif random.choice((True, False)) and value.isalnum():
|
||||
|
||||
# Alphanumeric
|
||||
new_value = random.choice(choices_alnum)
|
||||
|
||||
else:
|
||||
|
||||
# Default type
|
||||
new_value = random.choice(choices_alnum + choices_letter + choices_number)
|
||||
|
||||
# If we worked on a substring, apply changes to the whole string
|
||||
if value != attrib_value:
|
||||
# No ' around empty values
|
||||
if new_value != "" and value != "":
|
||||
new_value = "'" + new_value + "'"
|
||||
# Apply changes
|
||||
new_value = attrib_value.replace(unclean_value, new_value)
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print(
|
||||
"Fuzzing attribute #%i '%s' of tag #%i '%s'"
|
||||
% (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
|
||||
)
|
||||
|
||||
# Modify the attribute
|
||||
rand_elem.set(rand_attrib, new_value.decode("utf-8"))
|
||||
|
||||
def __del_node_and_children(self):
|
||||
|
||||
"""High-level minimizing mutator
|
||||
Delete a random node and its children (i.e. delete a random tree)"""
|
||||
|
||||
self.__del_node(True)
|
||||
|
||||
def __del_node_but_children(self):
|
||||
|
||||
"""High-level minimizing mutator
|
||||
Delete a random node but its children (i.e. link them to the parent of the deleted node)"""
|
||||
|
||||
self.__del_node(False)
|
||||
|
||||
def __del_node(self, delete_children):
|
||||
|
||||
""" Called by the __del_node_* mutators """
|
||||
|
||||
# Select a node to modify (but the root one)
|
||||
(rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True)
|
||||
|
||||
# If the document includes only a top-level element
|
||||
# Then we can't pick a element (given that "exclude_root_node = True")
|
||||
|
||||
# Is the document deep enough?
|
||||
if rand_elem is None:
|
||||
if self.verbose:
|
||||
print("Can't delete a node: document not deep enough!")
|
||||
return
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
but_or_and = "and" if delete_children else "but"
|
||||
print(
|
||||
"Deleting tag #%i '%s' %s its children"
|
||||
% (rand_elem_id, rand_elem.tag, but_or_and)
|
||||
)
|
||||
|
||||
if delete_children is False:
|
||||
# Link children of the random (soon to be deleted) node to its parent
|
||||
for child in rand_elem:
|
||||
rand_elem.getparent().append(child)
|
||||
|
||||
# Remove the node
|
||||
rand_elem.getparent().remove(rand_elem)
|
||||
|
||||
def __del_content(self):
|
||||
|
||||
"""High-level minimizing mutator
|
||||
Delete the attributes and children of a random node"""
|
||||
|
||||
# Select a node to modify
|
||||
(rand_elem_id, rand_elem) = self.__pick_element()
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
|
||||
|
||||
# Reset the node
|
||||
rand_elem.clear()
|
||||
|
||||
def __del_attribute(self):
|
||||
|
||||
"""High-level minimizing mutator
|
||||
Delete a random attribute from a random node"""
|
||||
|
||||
# Select a node to modify
|
||||
(rand_elem_id, rand_elem) = self.__pick_element()
|
||||
|
||||
# Get all the attributes
|
||||
attribs = rand_elem.keys()
|
||||
|
||||
# Is there attributes?
|
||||
if len(attribs) < 1:
|
||||
if self.verbose:
|
||||
print("No attribute: can't delete!")
|
||||
return
|
||||
|
||||
# Pick a random attribute
|
||||
rand_attrib_id = random.randint(0, len(attribs) - 1)
|
||||
rand_attrib = attribs[rand_attrib_id]
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print(
|
||||
"Deleting attribute #%i '%s' of tag #%i '%s'"
|
||||
% (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
|
||||
)
|
||||
|
||||
# Delete the attribute
|
||||
rand_elem.attrib.pop(rand_attrib)
|
||||
|
||||
def mutate(self, min=1, max=5):
|
||||
|
||||
""" Execute some high-level mutators between $min and $max times, then some medium-level ones """
|
||||
|
||||
# High-level mutation
|
||||
self.__exec_among(self, self.hl_mutators_all, min, max)
|
40
custom_mutators/examples/common.py
Normal file
40
custom_mutators/examples/common.py
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""
|
||||
Module containing functions shared between multiple AFL modules
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import random
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def randel(l):
|
||||
if not l:
|
||||
return None
|
||||
return l[random.randint(0, len(l) - 1)]
|
||||
|
||||
|
||||
def randel_pop(l):
|
||||
if not l:
|
||||
return None
|
||||
return l.pop(random.randint(0, len(l) - 1))
|
||||
|
||||
|
||||
def write_exc_example(data, exc):
|
||||
exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc))
|
||||
|
||||
if not os.path.exists(exc_name):
|
||||
with open(exc_name, "w") as f:
|
||||
f.write(data)
|
342
custom_mutators/examples/custom_mutator_helpers.h
Normal file
342
custom_mutators/examples/custom_mutator_helpers.h
Normal file
@ -0,0 +1,342 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
#define RAND_BELOW(limit) (rand() % (limit))
|
||||
|
||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||
#define BUF_VAR(type, name) \
|
||||
type * name##_buf; \
|
||||
size_t name##_size;
|
||||
/* this fills in `&structptr->something_buf, &structptr->something_size`. */
|
||||
#define BUF_PARAMS(struct, name) \
|
||||
(void **)&struct->name##_buf, &struct->name##_size
|
||||
|
||||
typedef struct {
|
||||
|
||||
} afl_t;
|
||||
|
||||
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
|
||||
|
||||
static s8 interesting_8[] = {INTERESTING_8};
|
||||
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
|
||||
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
|
||||
|
||||
switch (RAND_BELOW(12)) {
|
||||
|
||||
case 0: {
|
||||
|
||||
/* Flip a single bit somewhere. Spooky! */
|
||||
|
||||
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
|
||||
|
||||
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 1: {
|
||||
|
||||
/* Set byte to interesting value. */
|
||||
|
||||
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 2: {
|
||||
|
||||
/* Set word to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
|
||||
break;
|
||||
case 1:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 3: {
|
||||
|
||||
/* Set dword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 4: {
|
||||
|
||||
/* Set qword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 8) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 7) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u64 *)(out_buf + byte_idx) =
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u64 *)(out_buf + byte_idx) = SWAP64(
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 5: {
|
||||
|
||||
/* Randomly subtract from byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 6: {
|
||||
|
||||
/* Randomly add to byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 7: {
|
||||
|
||||
/* Randomly subtract from word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 8: {
|
||||
|
||||
/* Randomly add to word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 9: {
|
||||
|
||||
/* Randomly subtract from dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 10: {
|
||||
|
||||
/* Randomly add to dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 11: {
|
||||
|
||||
/* Just set a random byte to a random value. Because,
|
||||
why not. We use XOR with 1-255 to eliminate the
|
||||
possibility of a no-op. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This function calculates the next power of 2 greater or equal its argument.
|
||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
||||
*/
|
||||
static inline size_t next_pow2(size_t in) {
|
||||
|
||||
if (in == 0 || in > (size_t)-1)
|
||||
return 0; /* avoid undefined behaviour under-/overflow */
|
||||
size_t out = in - 1;
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
return out + 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(size_needed && *size >= size_needed)) return *buf;
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = realloc(*buf, next_size);
|
||||
*size = *buf ? next_size : 0;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
||||
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
|
||||
size_t *size2) {
|
||||
|
||||
void * scratch_buf = *buf1;
|
||||
size_t scratch_size = *size1;
|
||||
*buf1 = *buf2;
|
||||
*size1 = *size2;
|
||||
*buf2 = scratch_buf;
|
||||
*size2 = scratch_size;
|
||||
|
||||
}
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
376
custom_mutators/examples/example.c
Normal file
376
custom_mutators/examples/example.c
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
New Custom Mutator for AFL++
|
||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Shengtuo Hu <h1994st@gmail.com>
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
*/
|
||||
|
||||
// You need to use -I /path/to/AFLplusplus/include
|
||||
#include "custom_mutator_helpers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DATA_SIZE (100)
|
||||
|
||||
static const char *commands[] = {
|
||||
|
||||
"GET",
|
||||
"PUT",
|
||||
"DEL",
|
||||
|
||||
};
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_t *afl;
|
||||
|
||||
// any additional data here!
|
||||
size_t trim_size_current;
|
||||
int trimmming_steps;
|
||||
int cur_step;
|
||||
|
||||
// Reused buffers:
|
||||
BUF_VAR(u8, fuzz);
|
||||
BUF_VAR(u8, data);
|
||||
BUF_VAR(u8, havoc);
|
||||
BUF_VAR(u8, trim);
|
||||
BUF_VAR(u8, post_process);
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
/**
|
||||
* Initialize this custom mutator
|
||||
*
|
||||
* @param[in] afl a pointer to the internal state object. Can be ignored for
|
||||
* now.
|
||||
* @param[in] seed A seed for this mutator - the same seed should always mutate
|
||||
* in the same way.
|
||||
* @return Pointer to the data object this custom mutator instance should use.
|
||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||
* Return NULL on error.
|
||||
*/
|
||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed); // needed also by surgical_havoc_mutate()
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
* (Optional for now. Required in the future)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to input data to be mutated
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
|
||||
* error.
|
||||
* @param[in] add_buf Buffer containing the additional test case
|
||||
* @param[in] add_buf_size Size of the additional test case
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must not
|
||||
* produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf,
|
||||
size_t add_buf_size, // add_buf can be NULL
|
||||
size_t max_size) {
|
||||
|
||||
// Make sure that the packet size does not exceed the maximum size expected by
|
||||
// the fuzzer
|
||||
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
|
||||
|
||||
// maybe_grow is optimized to be quick for reused buffers.
|
||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
|
||||
if (!mutated_out) {
|
||||
|
||||
*out_buf = NULL;
|
||||
perror("custom mutator allocation (maybe_grow)");
|
||||
return 0; /* afl-fuzz will very likely error out after this. */
|
||||
|
||||
}
|
||||
|
||||
// Randomly select a command string to add as a header to the packet
|
||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||
|
||||
// Mutate the payload of the packet
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
|
||||
// Randomly perform one of the (no len modification) havoc mutations
|
||||
surgical_havoc_mutate(mutated_out, 3, mutated_size);
|
||||
|
||||
}
|
||||
|
||||
*out_buf = mutated_out;
|
||||
return mutated_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A post-processing function to use right before AFL writes the test case to
|
||||
* disk in order to execute the target.
|
||||
*
|
||||
* (Optional) If this functionality is not needed, simply don't define this
|
||||
* function.
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Buffer containing the test case to be executed
|
||||
* @param[in] buf_size Size of the test case
|
||||
* @param[out] out_buf Pointer to the buffer containing the test case after
|
||||
* processing. External library should allocate memory for out_buf.
|
||||
* The buf pointer may be reused (up to the given buf_size);
|
||||
* @return Size of the output buffer after processing or the needed amount.
|
||||
* A return of 0 indicates an error.
|
||||
*/
|
||||
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size, uint8_t **out_buf) {
|
||||
|
||||
uint8_t *post_process_buf =
|
||||
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
|
||||
if (!post_process_buf) {
|
||||
|
||||
perror("custom mutator realloc failed.");
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
memcpy(post_process_buf + 5, buf, buf_size);
|
||||
post_process_buf[0] = 'A';
|
||||
post_process_buf[1] = 'F';
|
||||
post_process_buf[2] = 'L';
|
||||
post_process_buf[3] = '+';
|
||||
post_process_buf[4] = '+';
|
||||
|
||||
*out_buf = post_process_buf;
|
||||
|
||||
return buf_size + 5;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called at the start of each trimming operation and receives
|
||||
* the initial buffer. It should return the amount of iteration steps possible
|
||||
* on this input (e.g. if your input has n elements and you want to remove
|
||||
* them one by one, return n, if you do a binary search, return log(n),
|
||||
* and so on...).
|
||||
*
|
||||
* If your trimming algorithm doesn't allow you to determine the amount of
|
||||
* (remaining) steps easily (esp. while running), then you can alternatively
|
||||
* return 1 here and always return 0 in post_trim until you are finished and
|
||||
* no steps remain. In that case, returning 1 in post_trim will end the
|
||||
* trimming routine. The whole current index/max iterations stuff is only used
|
||||
* to show progress.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param buf Buffer containing the test case
|
||||
* @param buf_size Size of the test case
|
||||
* @return The amount of possible iteration steps to trim the input.
|
||||
* negative on error.
|
||||
*/
|
||||
int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size) {
|
||||
|
||||
// We simply trim once
|
||||
data->trimmming_steps = 1;
|
||||
|
||||
data->cur_step = 0;
|
||||
|
||||
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
|
||||
|
||||
perror("init_trim grow");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
memcpy(data->trim_buf, buf, buf_size);
|
||||
|
||||
data->trim_size_current = buf_size;
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called for each trimming operation. It doesn't have any
|
||||
* arguments because we already have the initial buffer from init_trim and we
|
||||
* can memorize the current state in *data. This can also save
|
||||
* reparsing steps for each iteration. It should return the trimmed input
|
||||
* buffer, where the returned data must not exceed the initial input data in
|
||||
* length. Returning anything that is larger than the original data (passed
|
||||
* to init_trim) will result in a fatal abort of AFLFuzz.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[out] out_buf Pointer to the buffer containing the trimmed test case.
|
||||
* External library should allocate memory for out_buf.
|
||||
* AFL++ will not release the memory after saving the test case.
|
||||
* Keep a ref in *data.
|
||||
* *out_buf = NULL is treated as error.
|
||||
* @return Pointer to the size of the trimmed test case
|
||||
*/
|
||||
size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) {
|
||||
|
||||
*out_buf = data->trim_buf;
|
||||
|
||||
// Remove the last byte of the trimming input
|
||||
return data->trim_size_current - 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after each trim operation to inform you if your
|
||||
* trimming step was successful or not (in terms of coverage). If you receive
|
||||
* a failure here, you should reset your input to the last known good state.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param success Indicates if the last trim operation was successful.
|
||||
* @return The next trim iteration index (from 0 to the maximum amount of
|
||||
* steps returned in init_trim). negative ret on failure.
|
||||
*/
|
||||
int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
|
||||
|
||||
if (success) {
|
||||
|
||||
++data->cur_step;
|
||||
return data->cur_step;
|
||||
|
||||
}
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a single custom mutation on a given input.
|
||||
* This mutation is stacked with the other muatations in havoc.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to the input data to be mutated and the mutated
|
||||
* output
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf The output buffer. buf can be reused, if the content
|
||||
* fits. *out_buf = NULL is treated as error.
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must
|
||||
* not produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
|
||||
u8 **out_buf, size_t max_size) {
|
||||
|
||||
if (buf_size == 0) {
|
||||
|
||||
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
|
||||
if (!*out_buf) {
|
||||
|
||||
perror("custom havoc: maybe_grow");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
**out_buf = rand() % 256;
|
||||
buf_size = 1;
|
||||
|
||||
} else {
|
||||
|
||||
// We reuse buf here. It's legal and faster.
|
||||
*out_buf = buf;
|
||||
|
||||
}
|
||||
|
||||
size_t victim = rand() % buf_size;
|
||||
(*out_buf)[victim] += rand() % 10;
|
||||
|
||||
return buf_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability (in percentage) that afl_custom_havoc_mutation
|
||||
* is called in havoc. By default it is 6 %.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @return The probability (0-100).
|
||||
*/
|
||||
uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
|
||||
|
||||
return 5; // 5 %
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the fuzzer should fuzz the queue entry or not.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename File name of the test case in the queue entry
|
||||
* @return Return True(1) if the fuzzer will fuzz the queue entry, and
|
||||
* False(0) otherwise.
|
||||
*/
|
||||
uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for additional analysis (e.g. calling a different tool that does a
|
||||
* different kind of coverage and saves this for the custom mutator).
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename_new_queue File name of the new queue entry
|
||||
* @param filename_orig_queue File name of the original queue entry
|
||||
*/
|
||||
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
/* Additional analysis on the original or new test case */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->post_process_buf);
|
||||
free(data->havoc_buf);
|
||||
free(data->data_buf);
|
||||
free(data->fuzz_buf);
|
||||
free(data->trim_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
187
custom_mutators/examples/example.py
Normal file
187
custom_mutators/examples/example.py
Normal file
@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""
|
||||
Example Python Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
COMMANDS = [
|
||||
b"GET",
|
||||
b"PUT",
|
||||
b"DEL",
|
||||
b"AAAAAAAAAAAAAAAAA",
|
||||
]
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
"""
|
||||
random.seed(seed)
|
||||
|
||||
|
||||
def deinit():
|
||||
pass
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
"""
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@param buf: The buffer that should be mutated.
|
||||
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@type max_size: int
|
||||
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||
produce data larger than max_size.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
"""
|
||||
ret = bytearray(100)
|
||||
|
||||
ret[:3] = random.choice(COMMANDS)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
# Uncomment and implement the following methods if you want to use a custom
|
||||
# trimming algorithm. See also the documentation for a better API description.
|
||||
|
||||
# def init_trim(buf):
|
||||
# '''
|
||||
# Called per trimming iteration.
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer that should be trimmed.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The maximum number of trimming steps.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# # Initialize global variables
|
||||
#
|
||||
# # Figure out how many trimming steps are possible.
|
||||
# # If this is not possible for your trimming, you can
|
||||
# # return 1 instead and always return 0 in post_trim
|
||||
# # until you are done (then you return 1).
|
||||
#
|
||||
# return steps
|
||||
#
|
||||
# def trim():
|
||||
# '''
|
||||
# Called per trimming iteration.
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: A new bytearray containing the trimmed data.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# # Implement the actual trimming here
|
||||
#
|
||||
# return bytearray(...)
|
||||
#
|
||||
# def post_trim(success):
|
||||
# '''
|
||||
# Called after each trimming operation.
|
||||
#
|
||||
# @type success: bool
|
||||
# @param success: Indicates if the last trim operation was successful.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The next trim index (0 to max number of steps) where max
|
||||
# number of steps indicates the trimming is done.
|
||||
# '''
|
||||
# global ...
|
||||
#
|
||||
# if not success:
|
||||
# # Restore last known successful input, determine next index
|
||||
# else:
|
||||
# # Just determine the next index, based on what was successfully
|
||||
# # removed in the last step
|
||||
#
|
||||
# return next_index
|
||||
#
|
||||
# def post_process(buf):
|
||||
# '''
|
||||
# Called just before the execution to write the test case in the format
|
||||
# expected by the target
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer containing the test case to be executed
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: The buffer containing the test case after
|
||||
# '''
|
||||
# return buf
|
||||
#
|
||||
# def havoc_mutation(buf, max_size):
|
||||
# '''
|
||||
# Perform a single custom mutation on a given input.
|
||||
#
|
||||
# @type buf: bytearray
|
||||
# @param buf: The buffer that should be mutated.
|
||||
#
|
||||
# @type max_size: int
|
||||
# @param max_size: Maximum size of the mutated output. The mutation must not
|
||||
# produce data larger than max_size.
|
||||
#
|
||||
# @rtype: bytearray
|
||||
# @return: A new bytearray containing the mutated data
|
||||
# '''
|
||||
# return mutated_buf
|
||||
#
|
||||
# def havoc_mutation_probability():
|
||||
# '''
|
||||
# Called for each `havoc_mutation`. Return the probability (in percentage)
|
||||
# that `havoc_mutation` is called in havoc. Be default it is 6%.
|
||||
#
|
||||
# @rtype: int
|
||||
# @return: The probability (0-100)
|
||||
# '''
|
||||
# return prob
|
||||
#
|
||||
# def queue_get(filename):
|
||||
# '''
|
||||
# Called at the beginning of each fuzz iteration to determine whether the
|
||||
# test case should be fuzzed
|
||||
#
|
||||
# @type filename: str
|
||||
# @param filename: File name of the test case in the current queue entry
|
||||
#
|
||||
# @rtype: bool
|
||||
# @return: Return True if the custom mutator decides to fuzz the test case,
|
||||
# and False otherwise
|
||||
# '''
|
||||
# return True
|
||||
#
|
||||
# def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
# '''
|
||||
# Called after adding a new test case to the queue
|
||||
#
|
||||
# @type filename_new_queue: str
|
||||
# @param filename_new_queue: File name of the new queue entry
|
||||
#
|
||||
# @type filename_orig_queue: str
|
||||
# @param filename_orig_queue: File name of the original queue entry
|
||||
# '''
|
||||
# pass
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
american fuzzy lop - postprocessor library example
|
||||
american fuzzy lop++ - postprocessor library example
|
||||
--------------------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
Originally written by Michal Zalewski
|
||||
Edited by Dominik Maier, 2020
|
||||
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
@ -21,9 +22,9 @@
|
||||
in the targeted binary (as shown in ../libpng_no_checksum/). One possible
|
||||
exception is the process of fuzzing binary-only software in QEMU mode.
|
||||
|
||||
2) The use of postprocessors for anything other than checksums is questionable
|
||||
and may cause more harm than good. AFL is normally pretty good about
|
||||
dealing with length fields, magic values, etc.
|
||||
2) The use of postprocessors for anything other than checksums is
|
||||
questionable and may cause more harm than good. AFL is normally pretty good
|
||||
about dealing with length fields, magic values, etc.
|
||||
|
||||
3) Postprocessors that do anything non-trivial must be extremely robust to
|
||||
gracefully handle malformed data and other error conditions - otherwise,
|
||||
@ -38,27 +39,29 @@
|
||||
|
||||
gcc -shared -Wall -O3 post_library.so.c -o post_library.so
|
||||
|
||||
AFL will call the afl_postprocess() function for every mutated output buffer.
|
||||
From there, you have three choices:
|
||||
AFL will call the afl_custom_post_process() function for every mutated output
|
||||
buffer. From there, you have three choices:
|
||||
|
||||
1) If you don't want to modify the test case, simply return the original
|
||||
buffer pointer ('in_buf').
|
||||
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
|
||||
and return the original `len`.
|
||||
|
||||
NOTE: the following is currently NOT true, we abort in this case!
|
||||
2) If you want to skip this test case altogether and have AFL generate a
|
||||
new one, return NULL. Use this sparingly - it's faster than running
|
||||
the target program with patently useless inputs, but still wastes CPU
|
||||
time.
|
||||
new one, return 0 or set `*out_buf = NULL`.
|
||||
Use this sparingly - it's faster than running the target program
|
||||
with patently useless inputs, but still wastes CPU time.
|
||||
|
||||
3) If you want to modify the test case, allocate an appropriately-sized
|
||||
buffer, move the data into that buffer, make the necessary changes, and
|
||||
then return the new pointer. You can update *len if necessary, too.
|
||||
then return the new pointer as out_buf. Return an appropriate len
|
||||
afterwards.
|
||||
|
||||
Note that the buffer will *not* be freed for you. To avoid memory leaks,
|
||||
you need to free it or reuse it on subsequent calls (as shown below).
|
||||
|
||||
*** DO NOT MODIFY THE ORIGINAL 'in_buf' BUFFER. ***
|
||||
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
|
||||
|
||||
Aight. The example below shows a simple postprocessor that tries to make
|
||||
Alright. The example below shows a simple postprocessor that tries to make
|
||||
sure that all input files start with "GIF89a".
|
||||
|
||||
PS. If you don't like C, you can try out the unix-based wrapper from
|
||||
@ -74,46 +77,90 @@
|
||||
|
||||
#define HEADER "GIF89a"
|
||||
|
||||
typedef struct post_state {
|
||||
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
|
||||
} post_state_t;
|
||||
|
||||
void *afl_custom_init(void *afl) {
|
||||
|
||||
post_state_t *state = malloc(sizeof(post_state_t));
|
||||
if (!state) {
|
||||
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
||||
if (!state->buf) {
|
||||
|
||||
free(state);
|
||||
perror("calloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
/* The actual postprocessor routine called by afl-fuzz: */
|
||||
|
||||
const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
unsigned int* len) {
|
||||
|
||||
static unsigned char* saved_buf;
|
||||
unsigned char* new_buf;
|
||||
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
||||
unsigned int len, unsigned char **out_buf) {
|
||||
|
||||
/* Skip execution altogether for buffers shorter than 6 bytes (just to
|
||||
show how it's done). We can trust *len to be sane. */
|
||||
show how it's done). We can trust len to be sane. */
|
||||
|
||||
if (*len < strlen(HEADER)) return NULL;
|
||||
if (len < strlen(HEADER)) return 0;
|
||||
|
||||
/* Do nothing for buffers that already start with the expected header. */
|
||||
|
||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf;
|
||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate memory for new buffer, reusing previous allocation if
|
||||
possible. */
|
||||
|
||||
new_buf = realloc(saved_buf, *len);
|
||||
*out_buf = realloc(data->buf, len);
|
||||
|
||||
/* If we're out of memory, the most graceful thing to do is to return the
|
||||
original buffer and give up on modifying it. Let AFL handle OOM on its
|
||||
own later on. */
|
||||
|
||||
if (!new_buf) return in_buf;
|
||||
saved_buf = new_buf;
|
||||
if (!*out_buf) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Copy the original data to the new location. */
|
||||
|
||||
memcpy(new_buf, in_buf, *len);
|
||||
memcpy(*out_buf, in_buf, len);
|
||||
|
||||
/* Insert the new header. */
|
||||
|
||||
memcpy(new_buf, HEADER, strlen(HEADER));
|
||||
memcpy(*out_buf, HEADER, strlen(HEADER));
|
||||
|
||||
/* Return modified buffer. No need to update *len in this particular case,
|
||||
as we're not changing it. */
|
||||
/* Return the new len. It hasn't changed, so it's just len. */
|
||||
|
||||
return new_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Gets called afterwards */
|
||||
void afl_custom_deinit(post_state_t *data) {
|
||||
|
||||
free(data->buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/*
|
||||
american fuzzy lop - postprocessor for PNG
|
||||
american fuzzy lop++ - postprocessor for PNG
|
||||
------------------------------------------
|
||||
|
||||
Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
Adapted to the new API, 2020 by Dominik Maier
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -35,34 +36,67 @@
|
||||
|
||||
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
|
||||
|
||||
const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
unsigned int* len) {
|
||||
typedef struct post_state {
|
||||
|
||||
static unsigned char* saved_buf;
|
||||
static unsigned int saved_len;
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
|
||||
unsigned char* new_buf = (unsigned char*)in_buf;
|
||||
unsigned int pos = 8;
|
||||
} post_state_t;
|
||||
|
||||
void *afl_custom_init(void *afl) {
|
||||
|
||||
post_state_t *state = malloc(sizeof(post_state_t));
|
||||
if (!state) {
|
||||
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
||||
if (!state->buf) {
|
||||
|
||||
free(state);
|
||||
perror("calloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
||||
unsigned int len,
|
||||
const unsigned char **out_buf) {
|
||||
|
||||
unsigned char *new_buf = (unsigned char *)in_buf;
|
||||
unsigned int pos = 8;
|
||||
|
||||
/* Don't do anything if there's not enough room for the PNG header
|
||||
(8 bytes). */
|
||||
|
||||
if (*len < 8) return in_buf;
|
||||
if (len < 8) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
|
||||
don't have that, we can bail out. */
|
||||
|
||||
while (pos + 12 <= *len) {
|
||||
while (pos + 12 <= len) {
|
||||
|
||||
unsigned int chunk_len, real_cksum, file_cksum;
|
||||
|
||||
/* Chunk length is the first big-endian dword in the chunk. */
|
||||
|
||||
chunk_len = ntohl(*(uint32_t*)(in_buf + pos));
|
||||
chunk_len = ntohl(*(uint32_t *)(in_buf + pos));
|
||||
|
||||
/* Bail out if chunk size is too big or goes past EOF. */
|
||||
|
||||
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > *len) break;
|
||||
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
|
||||
|
||||
/* Chunk checksum is calculated for chunk ID (dword) and the actual
|
||||
payload. */
|
||||
@ -71,7 +105,7 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
/* The in-file checksum is the last dword past the chunk data. */
|
||||
|
||||
file_cksum = *(uint32_t*)(in_buf + pos + 8 + chunk_len);
|
||||
file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len);
|
||||
|
||||
/* If the checksums do not match, we need to fix the file. */
|
||||
|
||||
@ -82,23 +116,29 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
if (new_buf == in_buf) {
|
||||
|
||||
if (*len <= saved_len) {
|
||||
if (len <= data->size) {
|
||||
|
||||
new_buf = saved_buf;
|
||||
new_buf = data->buf;
|
||||
|
||||
} else {
|
||||
|
||||
new_buf = realloc(saved_buf, UP4K(*len));
|
||||
if (!new_buf) return in_buf;
|
||||
saved_buf = new_buf;
|
||||
saved_len = UP4K(*len);
|
||||
memcpy(new_buf, in_buf, *len);
|
||||
new_buf = realloc(data->buf, UP4K(len));
|
||||
if (!new_buf) {
|
||||
|
||||
*out_buf = in_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
data->buf = new_buf;
|
||||
data->size = UP4K(len);
|
||||
memcpy(new_buf, in_buf, len);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*(uint32_t*)(new_buf + pos + 8 + chunk_len) = real_cksum;
|
||||
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
|
||||
|
||||
}
|
||||
|
||||
@ -108,6 +148,16 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
|
||||
}
|
||||
|
||||
return new_buf;
|
||||
*out_buf = new_buf;
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Gets called afterwards */
|
||||
void afl_custom_deinit(post_state_t *data) {
|
||||
|
||||
free(data->buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
66
custom_mutators/examples/simple-chunk-replace.py
Normal file
66
custom_mutators/examples/simple-chunk-replace.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""
|
||||
Simple Chunk Cross-Over Replacement Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
|
||||
@license:
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
@contact: choller@mozilla.com
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
@type seed: int
|
||||
@param seed: A 32-bit random value
|
||||
"""
|
||||
# Seed our RNG
|
||||
random.seed(seed)
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
"""
|
||||
Called per fuzzing iteration.
|
||||
|
||||
@type buf: bytearray
|
||||
@param buf: The buffer that should be mutated.
|
||||
|
||||
@type add_buf: bytearray
|
||||
@param add_buf: A second buffer that can be used as mutation source.
|
||||
|
||||
@type max_size: int
|
||||
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||
produce data larger than max_size.
|
||||
|
||||
@rtype: bytearray
|
||||
@return: A new bytearray containing the mutated data
|
||||
"""
|
||||
# Make a copy of our input buffer for returning
|
||||
ret = bytearray(buf)
|
||||
|
||||
# Take a random fragment length between 2 and 32 (or less if add_buf is shorter)
|
||||
fragment_len = random.randint(1, min(len(add_buf), 32))
|
||||
|
||||
# Determine a random source index where to take the data chunk from
|
||||
rand_src_idx = random.randint(0, len(add_buf) - fragment_len)
|
||||
|
||||
# Determine a random destination index where to put the data chunk
|
||||
rand_dst_idx = random.randint(0, len(buf))
|
||||
|
||||
# Make the chunk replacement
|
||||
ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[
|
||||
rand_src_idx : rand_src_idx + fragment_len
|
||||
]
|
||||
|
||||
# Return data
|
||||
return ret
|
74
custom_mutators/examples/simple_example.c
Normal file
74
custom_mutators/examples/simple_example.c
Normal file
@ -0,0 +1,74 @@
|
||||
// This simple example just creates random buffer <= 100 filled with 'A'
|
||||
// needs -I /path/to/AFLplusplus/include
|
||||
#include "custom_mutator_helpers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _FIXED_CHAR
|
||||
#define _FIXED_CHAR 0x41
|
||||
#endif
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_t *afl;
|
||||
|
||||
// Reused buffers:
|
||||
BUF_VAR(u8, fuzz);
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed);
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf,
|
||||
size_t add_buf_size, // add_buf can be NULL
|
||||
size_t max_size) {
|
||||
|
||||
int size = (rand() % 100) + 1;
|
||||
if (size > max_size) size = max_size;
|
||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
|
||||
if (!mutated_out) {
|
||||
|
||||
*out_buf = NULL;
|
||||
perror("custom mutator allocation (maybe_grow)");
|
||||
return 0; /* afl-fuzz will very likely error out after this. */
|
||||
|
||||
}
|
||||
|
||||
memset(mutated_out, _FIXED_CHAR, size);
|
||||
|
||||
*out_buf = mutated_out;
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->fuzz_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
123
custom_mutators/examples/wrapper_afl_min.py
Normal file
123
custom_mutators/examples/wrapper_afl_min.py
Normal file
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from XmlMutatorMin import XmlMutatorMin
|
||||
|
||||
# Default settings (production mode)
|
||||
|
||||
__mutator__ = None
|
||||
__seed__ = "RANDOM"
|
||||
__log__ = False
|
||||
__log_file__ = "wrapper.log"
|
||||
|
||||
|
||||
# AFL functions
|
||||
def log(text):
|
||||
"""
|
||||
Logger
|
||||
"""
|
||||
|
||||
global __seed__
|
||||
global __log__
|
||||
global __log_file__
|
||||
|
||||
if __log__:
|
||||
with open(__log_file__, "a") as logf:
|
||||
logf.write("[%s] %s\n" % (__seed__, text))
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
"""
|
||||
|
||||
global __mutator__
|
||||
global __seed__
|
||||
|
||||
# Get the seed
|
||||
__seed__ = seed
|
||||
|
||||
# Create a global mutation class
|
||||
try:
|
||||
__mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
|
||||
log("init(): Mutator created")
|
||||
except RuntimeError as e:
|
||||
log("init(): Can't create mutator: %s" % e.message)
|
||||
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
"""
|
||||
Called for each fuzzing iteration.
|
||||
"""
|
||||
|
||||
global __mutator__
|
||||
|
||||
# Do we have a working mutator object?
|
||||
if __mutator__ is None:
|
||||
log("fuzz(): Can't fuzz, no mutator available")
|
||||
return buf
|
||||
|
||||
# Try to use the AFL buffer
|
||||
via_buffer = True
|
||||
|
||||
# Interpret the AFL buffer (an array of bytes) as a string
|
||||
if via_buffer:
|
||||
try:
|
||||
buf_str = str(buf)
|
||||
log("fuzz(): AFL buffer converted to a string")
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't convert AFL buffer to a string")
|
||||
|
||||
# Load XML from the AFL string
|
||||
if via_buffer:
|
||||
try:
|
||||
__mutator__.init_from_string(buf_str)
|
||||
log(
|
||||
"fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)"
|
||||
% len(buf_str)
|
||||
)
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||
|
||||
# If init from AFL buffer wasn't succesful
|
||||
if not via_buffer:
|
||||
log("fuzz(): Returning unmodified AFL buffer")
|
||||
return buf
|
||||
|
||||
# Sucessful initialization -> mutate
|
||||
try:
|
||||
__mutator__.mutate(max=5)
|
||||
log("fuzz(): Input mutated")
|
||||
except Exception:
|
||||
log("fuzz(): Can't mutate input => returning buf")
|
||||
return buf
|
||||
|
||||
# Convert mutated data to a array of bytes
|
||||
try:
|
||||
data = bytearray(__mutator__.save_to_string())
|
||||
log("fuzz(): Mutated data converted as bytes")
|
||||
except Exception:
|
||||
log("fuzz(): Can't convert mutated data to bytes => returning buf")
|
||||
return buf
|
||||
|
||||
# Everything went fine, returning mutated content
|
||||
log("fuzz(): Returning %d bytes" % len(data))
|
||||
return data
|
||||
|
||||
|
||||
# Main (for debug)
|
||||
if __name__ == "__main__":
|
||||
|
||||
__log__ = True
|
||||
__log_file__ = "/dev/stdout"
|
||||
__seed__ = "RANDOM"
|
||||
|
||||
init(__seed__)
|
||||
|
||||
in_1 = bytearray(
|
||||
"<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>"
|
||||
)
|
||||
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
||||
out = fuzz(in_1, in_2)
|
||||
print(out)
|
1
custom_mutators/grammar_mutator/GRAMMAR_VERSION
Normal file
1
custom_mutators/grammar_mutator/GRAMMAR_VERSION
Normal file
@ -0,0 +1 @@
|
||||
b79d51a
|
6
custom_mutators/grammar_mutator/README.md
Normal file
6
custom_mutators/grammar_mutator/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# Grammar-Mutator
|
||||
|
||||
This is just a stub directory that will clone the real grammar mutator
|
||||
directory.
|
||||
|
||||
Execute `./build_grammar_mutator.sh` to set everything up.
|
140
custom_mutators/grammar_mutator/build_grammar_mutator.sh
Executable file
140
custom_mutators/grammar_mutator/build_grammar_mutator.sh
Executable file
@ -0,0 +1,140 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop++ - unicorn mode build script
|
||||
# ------------------------------------------------
|
||||
#
|
||||
# Originally written by Nathan Voss <njvoss99@gmail.com>
|
||||
#
|
||||
# Adapted from code by Andrew Griffiths <agriffiths@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
|
||||
#
|
||||
# CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
# <andreafioraldi@gmail.com>
|
||||
#
|
||||
# Copyright 2017 Battelle Memorial Institute. 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 script downloads, patches, and builds a version of Unicorn with
|
||||
# minor tweaks to allow Unicorn-emulated binaries to be run under
|
||||
# afl-fuzz.
|
||||
#
|
||||
# The modifications reside in patches/*. The standalone Unicorn library
|
||||
# will be written to /usr/lib/libunicornafl.so, and the Python bindings
|
||||
# will be installed system-wide.
|
||||
#
|
||||
# You must make sure that Unicorn Engine is not already installed before
|
||||
# running this script. If it is, please uninstall it first.
|
||||
|
||||
GRAMMAR_VERSION="$(cat ./GRAMMAR_VERSION)"
|
||||
GRAMMAR_REPO="https://github.com/AFLplusplus/grammar-mutator"
|
||||
|
||||
echo "================================================="
|
||||
echo "Grammar Mutator build script"
|
||||
echo "================================================="
|
||||
echo
|
||||
|
||||
echo "[*] Performing basic sanity checks..."
|
||||
|
||||
PLT=`uname -s`
|
||||
|
||||
if [ ! -f "../../config.h" ]; then
|
||||
|
||||
echo "[-] Error: key files not found - wrong working directory?"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
if [ "$PLT" = "Darwin" ]; then
|
||||
CORES=`sysctl -n hw.ncpu`
|
||||
TARCMD=tar
|
||||
fi
|
||||
|
||||
if [ "$PLT" = "FreeBSD" ]; then
|
||||
MAKECMD=gmake
|
||||
CORES=`sysctl -n hw.ncpu`
|
||||
TARCMD=gtar
|
||||
fi
|
||||
|
||||
if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then
|
||||
MAKECMD=gmake
|
||||
CORES=`sysctl -n hw.ncpu`
|
||||
TARCMD=gtar
|
||||
fi
|
||||
|
||||
PREREQ_NOTFOUND=
|
||||
for i in git $MAKECMD $TARCMD; do
|
||||
|
||||
T=`command -v "$i" 2>/dev/null`
|
||||
|
||||
if [ "$T" = "" ]; then
|
||||
|
||||
echo "[-] Error: '$i' not found. Run 'sudo apt-get install $i' or similar."
|
||||
PREREQ_NOTFOUND=1
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if echo "$CC" | grep -qF /afl-; then
|
||||
|
||||
echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
|
||||
PREREQ_NOTFOUND=1
|
||||
|
||||
fi
|
||||
|
||||
if [ "$PREREQ_NOTFOUND" = "1" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[+] All checks passed!"
|
||||
|
||||
echo "[*] Making sure grammar mutator is checked out"
|
||||
|
||||
git status 1>/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[*] initializing grammar mutator submodule"
|
||||
git submodule init || exit 1
|
||||
git submodule update ./grammar_mutator 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning grammar mutator"
|
||||
test -d grammar_mutator || {
|
||||
CNT=1
|
||||
while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone grammar_mutator (attempt $CNT/3)"
|
||||
git clone "$GRAMMAR_REPO"
|
||||
CNT=`expr "$CNT" + 1`
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
echo "[+] Got grammar mutator."
|
||||
|
||||
cd "grammar_mutator" || exit 1
|
||||
echo "[*] Checking out $GRAMMAR_VERSION"
|
||||
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
|
||||
git checkout "$GRAMMAR_VERSION" || exit 1
|
||||
echo "[*] Downloading antlr..."
|
||||
wget -c https://www.antlr.org/download/antlr-4.8-complete.jar
|
||||
cd ..
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "[+] All successfully prepared!"
|
||||
echo "[!] To build for your grammar just do:"
|
||||
echo " cd grammar_mutator"
|
||||
echo " make GRAMMAR_FILE=/path/to/your/grammar"
|
||||
echo "[+] You will find a JSON and RUBY grammar in grammar_mutator/grammars to play with."
|
||||
echo
|
1
custom_mutators/grammar_mutator/grammar_mutator
Submodule
1
custom_mutators/grammar_mutator/grammar_mutator
Submodule
Submodule custom_mutators/grammar_mutator/grammar_mutator added at b79d51a8da
50
custom_mutators/grammar_mutator/update_grammar_ref.sh
Executable file
50
custom_mutators/grammar_mutator/update_grammar_ref.sh
Executable file
@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
|
||||
##################################################
|
||||
# AFL++ tool to update a git ref.
|
||||
# Usage: ./<script>.sh <new commit hash>
|
||||
# If no commit hash was provided, it'll take HEAD.
|
||||
##################################################
|
||||
|
||||
TOOL="grammar mutator"
|
||||
VERSION_FILE='./GRAMMAR_VERSION'
|
||||
REPO_FOLDER='./grammar_mutator'
|
||||
THIS_SCRIPT=`basename $0`
|
||||
BRANCH="stable"
|
||||
|
||||
NEW_VERSION="$1"
|
||||
|
||||
if [ "$NEW_VERSION" = "-h" ]; then
|
||||
echo "Internal script to update bound $TOOL version."
|
||||
echo
|
||||
echo "Usage: $THIS_SCRIPT <new commit hash>"
|
||||
echo "If no commit hash is provided, will use HEAD."
|
||||
echo "-h to show this help screen."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git submodule init && git submodule update ./grammar_mutator || exit 1
|
||||
cd "$REPO_FOLDER" || exit 1
|
||||
git fetch origin $BRANCH 1>/dev/null || exit 1
|
||||
git stash 1>/dev/null 2>/dev/null
|
||||
git stash drop 1>/dev/null 2>/dev/null
|
||||
git checkout $BRANCH
|
||||
|
||||
if [ -z "$NEW_VERSION" ]; then
|
||||
# No version provided, take HEAD.
|
||||
NEW_VERSION=$(git rev-parse --short HEAD)
|
||||
fi
|
||||
|
||||
if [ -z "$NEW_VERSION" ]; then
|
||||
echo "Error getting version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git checkout "$NEW_VERSION" || exit 1
|
||||
|
||||
cd ..
|
||||
|
||||
rm "$VERSION_FILE"
|
||||
echo "$NEW_VERSION" > "$VERSION_FILE"
|
||||
|
||||
echo "Done. New $TOOL version is $NEW_VERSION."
|
17
custom_mutators/honggfuzz/Makefile
Normal file
17
custom_mutators/honggfuzz/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
|
||||
|
||||
all: honggfuzz-mutator.so
|
||||
|
||||
honggfuzz-mutator.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz-mutator.so honggfuzz.c mangle.c ../../src/afl-performance.c
|
||||
|
||||
update:
|
||||
@# seriously? --unlink is a dud option? sigh ...
|
||||
rm -f mangle.c mangle.h honggfuzz.h
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.c
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.h
|
||||
wget --unlink https://github.com/google/honggfuzz/raw/master/honggfuzz.h
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ *.so core
|
12
custom_mutators/honggfuzz/README.md
Normal file
12
custom_mutators/honggfuzz/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# custum mutator: honggfuzz mangle
|
||||
|
||||
this is the honggfuzz mutator in mangle.c as a custom mutator
|
||||
module for afl++. It is the original mangle.c, mangle.h and honggfuzz.h
|
||||
with a lot of mocking around it :-)
|
||||
|
||||
just type `make` to build
|
||||
|
||||
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/honggfuzz/honggfuzz-mutator.so afl-fuzz ...```
|
||||
|
||||
> Original repository: https://github.com/google/honggfuzz
|
||||
> Source commit: d0fbcb0373c32436b8fb922e6937da93b17291f5
|
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
22
custom_mutators/honggfuzz/custom_mutator_helpers.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "afl-fuzz.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||
#define BUF_VAR(type, name) \
|
||||
type * name##_buf; \
|
||||
size_t name##_size;
|
||||
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
|
||||
#define BUF_PARAMS(struct, name) \
|
||||
(void **)&struct->name##_buf, &struct->name##_size
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
144
custom_mutators/honggfuzz/honggfuzz.c
Normal file
144
custom_mutators/honggfuzz/honggfuzz.c
Normal file
@ -0,0 +1,144 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "custom_mutator_helpers.h"
|
||||
#include "mangle.h"
|
||||
|
||||
#define NUMBER_OF_MUTATIONS 5
|
||||
|
||||
uint8_t * queue_input;
|
||||
size_t queue_input_size;
|
||||
afl_state_t * afl_struct;
|
||||
run_t run;
|
||||
honggfuzz_t global;
|
||||
struct _dynfile_t dynfile;
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
run_t * run;
|
||||
u8 * mutator_buf;
|
||||
unsigned int seed;
|
||||
unsigned int extras_cnt, a_extras_cnt;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
|
||||
|
||||
free(data);
|
||||
perror("mutator_buf alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
run.dynfile = &dynfile;
|
||||
run.global = &global;
|
||||
data->afl = afl;
|
||||
data->seed = seed;
|
||||
data->run = &run;
|
||||
afl_struct = afl;
|
||||
|
||||
run.global->mutate.maxInputSz = MAX_FILE;
|
||||
run.global->mutate.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||
run.mutationsPerRun = NUMBER_OF_MUTATIONS;
|
||||
run.global->timing.lastCovUpdate = 6;
|
||||
|
||||
// global->feedback.cmpFeedback
|
||||
// global->feedback.cmpFeedbackMap
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/* When a new queue entry is added we check if there are new dictionary
|
||||
entries to add to honggfuzz structure */
|
||||
|
||||
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
if (run.global->mutate.dictionaryCnt >= 1024) return;
|
||||
|
||||
while (data->extras_cnt < data->afl->extras_cnt &&
|
||||
run.global->mutate.dictionaryCnt < 1024) {
|
||||
|
||||
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||
data->afl->extras[data->extras_cnt].data,
|
||||
data->afl->extras[data->extras_cnt].len);
|
||||
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||
data->afl->extras[data->extras_cnt].len;
|
||||
run.global->mutate.dictionaryCnt++;
|
||||
data->extras_cnt++;
|
||||
|
||||
}
|
||||
|
||||
while (data->a_extras_cnt < data->afl->a_extras_cnt &&
|
||||
run.global->mutate.dictionaryCnt < 1024) {
|
||||
|
||||
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
|
||||
data->afl->a_extras[data->a_extras_cnt].data,
|
||||
data->afl->a_extras[data->a_extras_cnt].len);
|
||||
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
|
||||
data->afl->a_extras[data->a_extras_cnt].len;
|
||||
run.global->mutate.dictionaryCnt++;
|
||||
data->a_extras_cnt++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* we could set only_printable if is_ascii is set ... let's see
|
||||
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) {
|
||||
|
||||
//run.global->cfg.only_printable = ...
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/* here we run the honggfuzz mutator, which is really good */
|
||||
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
|
||||
size_t max_size) {
|
||||
|
||||
/* set everything up, costly ... :( */
|
||||
memcpy(data->mutator_buf, buf, buf_size);
|
||||
queue_input = data->mutator_buf;
|
||||
run.dynfile->data = data->mutator_buf;
|
||||
queue_input_size = buf_size;
|
||||
run.dynfile->size = buf_size;
|
||||
*out_buf = data->mutator_buf;
|
||||
|
||||
/* the mutation */
|
||||
mangle_mangleContent(&run, NUMBER_OF_MUTATIONS);
|
||||
|
||||
/* return size of mutated data */
|
||||
return run.dynfile->size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->mutator_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
386
custom_mutators/honggfuzz/honggfuzz.h
Normal file
386
custom_mutators/honggfuzz/honggfuzz.h
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
*
|
||||
* honggfuzz - core structures and macros
|
||||
* -----------------------------------------
|
||||
*
|
||||
* Author: Robert Swiecki <swiecki@google.com>
|
||||
*
|
||||
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HF_HONGGFUZZ_H_
|
||||
#define _HF_HONGGFUZZ_H_
|
||||
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "libhfcommon/util.h"
|
||||
|
||||
#define PROG_NAME "honggfuzz"
|
||||
#define PROG_VERSION "2.4"
|
||||
|
||||
/* Name of the template which will be replaced with the proper name of the file */
|
||||
#define _HF_FILE_PLACEHOLDER "___FILE___"
|
||||
|
||||
/* Default name of the report created with some architectures */
|
||||
#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
|
||||
|
||||
/* Default stack-size of created threads. */
|
||||
#define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */
|
||||
|
||||
/* Name of envvar which indicates sequential number of fuzzer */
|
||||
#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
|
||||
|
||||
/* Name of envvar which indicates that the netDriver should be used */
|
||||
#define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
|
||||
|
||||
/* Name of envvar which indicates honggfuzz's log level in use */
|
||||
#define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
|
||||
|
||||
/* Number of crash verifier iterations before tag crash as stable */
|
||||
#define _HF_VERIFIER_ITER 5
|
||||
|
||||
/* Size (in bytes) for report data to be stored in stack before written to file */
|
||||
#define _HF_REPORT_SIZE 32768
|
||||
|
||||
/* Perf bitmap size */
|
||||
#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
|
||||
#define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
|
||||
/* Maximum number of PC guards (=trace-pc-guard) we support */
|
||||
#define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
|
||||
|
||||
/* Maximum size of the input file in bytes (1 MiB) */
|
||||
#define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL)
|
||||
|
||||
/* Default maximum size of produced inputs */
|
||||
#define _HF_INPUT_DEFAULT_SIZE (1024ULL * 8)
|
||||
|
||||
/* Per-thread bitmap */
|
||||
#define _HF_PERTHREAD_BITMAP_FD 1018
|
||||
/* FD used to report back used int/str constants from the fuzzed process */
|
||||
#define _HF_CMP_BITMAP_FD 1019
|
||||
/* FD used to log inside the child process */
|
||||
#define _HF_LOG_FD 1020
|
||||
/* FD used to represent the input file */
|
||||
#define _HF_INPUT_FD 1021
|
||||
/* FD used to pass coverage feedback from the fuzzed process */
|
||||
#define _HF_COV_BITMAP_FD 1022
|
||||
#define _HF_BITMAP_FD _HF_COV_BITMAP_FD /* Old name for _HF_COV_BITMAP_FD */
|
||||
/* FD used to pass data to a persistent process */
|
||||
#define _HF_PERSISTENT_FD 1023
|
||||
|
||||
/* Input file as a string */
|
||||
#define _HF_INPUT_FILE_PATH "/dev/fd/" HF_XSTR(_HF_INPUT_FD)
|
||||
|
||||
/* Maximum number of supported execve() args */
|
||||
#define _HF_ARGS_MAX 2048
|
||||
|
||||
/* Message indicating that the fuzzed process is ready for new data */
|
||||
static const uint8_t HFReadyTag = 'R';
|
||||
|
||||
/* Maximum number of active fuzzing threads */
|
||||
#define _HF_THREAD_MAX 1024U
|
||||
|
||||
/* Persistent-binary signature - if found within file, it means it's a persistent mode binary */
|
||||
#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
|
||||
/* HF NetDriver signature - if found within file, it means it's a NetDriver-based binary */
|
||||
#define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
|
||||
|
||||
/* printf() nonmonetary separator. According to MacOSX's man it's supported there as well */
|
||||
#define _HF_NONMON_SEP "'"
|
||||
|
||||
typedef enum {
|
||||
_HF_DYNFILE_NONE = 0x0,
|
||||
_HF_DYNFILE_INSTR_COUNT = 0x1,
|
||||
_HF_DYNFILE_BRANCH_COUNT = 0x2,
|
||||
_HF_DYNFILE_BTS_EDGE = 0x10,
|
||||
_HF_DYNFILE_IPT_BLOCK = 0x20,
|
||||
_HF_DYNFILE_SOFT = 0x40,
|
||||
} dynFileMethod_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t cpuInstrCnt;
|
||||
uint64_t cpuBranchCnt;
|
||||
uint64_t bbCnt;
|
||||
uint64_t newBBCnt;
|
||||
uint64_t softCntPc;
|
||||
uint64_t softCntEdge;
|
||||
uint64_t softCntCmp;
|
||||
} hwcnt_t;
|
||||
|
||||
typedef enum {
|
||||
_HF_STATE_UNSET = 0,
|
||||
_HF_STATE_STATIC,
|
||||
_HF_STATE_DYNAMIC_DRY_RUN,
|
||||
_HF_STATE_DYNAMIC_MAIN,
|
||||
_HF_STATE_DYNAMIC_MINIMIZE,
|
||||
} fuzzState_t;
|
||||
|
||||
typedef enum {
|
||||
HF_MAYBE = -1,
|
||||
HF_NO = 0,
|
||||
HF_YES = 1,
|
||||
} tristate_t;
|
||||
|
||||
struct _dynfile_t {
|
||||
size_t size;
|
||||
uint64_t cov[4];
|
||||
size_t idx;
|
||||
int fd;
|
||||
uint64_t timeExecUSecs;
|
||||
char path[PATH_MAX];
|
||||
struct _dynfile_t* src;
|
||||
uint32_t refs;
|
||||
uint8_t* data;
|
||||
TAILQ_ENTRY(_dynfile_t) pointers;
|
||||
};
|
||||
|
||||
typedef struct _dynfile_t dynfile_t;
|
||||
|
||||
struct strings_t {
|
||||
size_t len;
|
||||
TAILQ_ENTRY(strings_t) pointers;
|
||||
char s[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t pcGuardMap[_HF_PC_GUARD_MAX];
|
||||
uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
|
||||
uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
|
||||
uint64_t pidNewPC[_HF_THREAD_MAX];
|
||||
uint64_t pidNewEdge[_HF_THREAD_MAX];
|
||||
uint64_t pidNewCmp[_HF_THREAD_MAX];
|
||||
uint64_t guardNb;
|
||||
uint64_t pidTotalPC[_HF_THREAD_MAX];
|
||||
uint64_t pidTotalEdge[_HF_THREAD_MAX];
|
||||
uint64_t pidTotalCmp[_HF_THREAD_MAX];
|
||||
} feedback_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t cnt;
|
||||
struct {
|
||||
uint8_t val[32];
|
||||
uint32_t len;
|
||||
} valArr[1024 * 16];
|
||||
} cmpfeedback_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
size_t threadsMax;
|
||||
size_t threadsFinished;
|
||||
uint32_t threadsActiveCnt;
|
||||
pthread_t mainThread;
|
||||
pid_t mainPid;
|
||||
pthread_t threads[_HF_THREAD_MAX];
|
||||
} threads;
|
||||
struct {
|
||||
const char* inputDir;
|
||||
const char* outputDir;
|
||||
DIR* inputDirPtr;
|
||||
size_t fileCnt;
|
||||
size_t testedFileCnt;
|
||||
const char* fileExtn;
|
||||
size_t maxFileSz;
|
||||
size_t newUnitsAdded;
|
||||
char workDir[PATH_MAX];
|
||||
const char* crashDir;
|
||||
const char* covDirNew;
|
||||
bool saveUnique;
|
||||
bool saveSmaller;
|
||||
size_t dynfileqMaxSz;
|
||||
size_t dynfileqCnt;
|
||||
dynfile_t* dynfileqCurrent;
|
||||
dynfile_t* dynfileq2Current;
|
||||
TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq;
|
||||
bool exportFeedback;
|
||||
} io;
|
||||
struct {
|
||||
int argc;
|
||||
const char* const* cmdline;
|
||||
bool nullifyStdio;
|
||||
bool fuzzStdin;
|
||||
const char* externalCommand;
|
||||
const char* postExternalCommand;
|
||||
const char* feedbackMutateCommand;
|
||||
bool netDriver;
|
||||
bool persistent;
|
||||
uint64_t asLimit;
|
||||
uint64_t rssLimit;
|
||||
uint64_t dataLimit;
|
||||
uint64_t coreLimit;
|
||||
uint64_t stackLimit;
|
||||
bool clearEnv;
|
||||
char* env_ptrs[128];
|
||||
char env_vals[128][4096];
|
||||
sigset_t waitSigSet;
|
||||
} exe;
|
||||
struct {
|
||||
time_t timeStart;
|
||||
time_t runEndTime;
|
||||
time_t tmOut;
|
||||
time_t lastCovUpdate;
|
||||
int64_t timeOfLongestUnitUSecs;
|
||||
bool tmoutVTALRM;
|
||||
} timing;
|
||||
struct {
|
||||
struct {
|
||||
uint8_t val[256];
|
||||
size_t len;
|
||||
} dictionary[1024];
|
||||
size_t dictionaryCnt;
|
||||
const char* dictionaryFile;
|
||||
size_t mutationsMax;
|
||||
unsigned mutationsPerRun;
|
||||
size_t maxInputSz;
|
||||
} mutate;
|
||||
struct {
|
||||
bool useScreen;
|
||||
char cmdline_txt[65];
|
||||
int64_t lastDisplayUSecs;
|
||||
} display;
|
||||
struct {
|
||||
bool useVerifier;
|
||||
bool exitUponCrash;
|
||||
const char* reportFile;
|
||||
size_t dynFileIterExpire;
|
||||
bool only_printable;
|
||||
bool minimize;
|
||||
bool switchingToFDM;
|
||||
} cfg;
|
||||
struct {
|
||||
bool enable;
|
||||
bool del_report;
|
||||
} sanitizer;
|
||||
struct {
|
||||
fuzzState_t state;
|
||||
feedback_t* covFeedbackMap;
|
||||
int covFeedbackFd;
|
||||
cmpfeedback_t* cmpFeedbackMap;
|
||||
int cmpFeedbackFd;
|
||||
bool cmpFeedback;
|
||||
const char* blocklistFile;
|
||||
uint64_t* blocklist;
|
||||
size_t blocklistCnt;
|
||||
bool skipFeedbackOnTimeout;
|
||||
uint64_t maxCov[4];
|
||||
dynFileMethod_t dynFileMethod;
|
||||
hwcnt_t hwCnts;
|
||||
} feedback;
|
||||
struct {
|
||||
size_t mutationsCnt;
|
||||
size_t crashesCnt;
|
||||
size_t uniqueCrashesCnt;
|
||||
size_t verifiedCrashesCnt;
|
||||
size_t blCrashesCnt;
|
||||
size_t timeoutedCnt;
|
||||
} cnts;
|
||||
struct {
|
||||
bool enabled;
|
||||
int serverSocket;
|
||||
int clientSocket;
|
||||
} socketFuzzer;
|
||||
struct {
|
||||
pthread_rwlock_t dynfileq;
|
||||
pthread_mutex_t feedback;
|
||||
pthread_mutex_t report;
|
||||
pthread_mutex_t state;
|
||||
pthread_mutex_t input;
|
||||
pthread_mutex_t timing;
|
||||
} mutex;
|
||||
|
||||
/* For the Linux code */
|
||||
struct {
|
||||
int exeFd;
|
||||
uint64_t dynamicCutOffAddr;
|
||||
bool disableRandomization;
|
||||
void* ignoreAddr;
|
||||
const char* symsBlFile;
|
||||
char** symsBl;
|
||||
size_t symsBlCnt;
|
||||
const char* symsWlFile;
|
||||
char** symsWl;
|
||||
size_t symsWlCnt;
|
||||
uintptr_t cloneFlags;
|
||||
tristate_t useNetNs;
|
||||
bool kernelOnly;
|
||||
bool useClone;
|
||||
} arch_linux;
|
||||
/* For the NetBSD code */
|
||||
struct {
|
||||
void* ignoreAddr;
|
||||
const char* symsBlFile;
|
||||
char** symsBl;
|
||||
size_t symsBlCnt;
|
||||
const char* symsWlFile;
|
||||
char** symsWl;
|
||||
size_t symsWlCnt;
|
||||
} arch_netbsd;
|
||||
} honggfuzz_t;
|
||||
|
||||
typedef enum {
|
||||
_HF_RS_UNKNOWN = 0,
|
||||
_HF_RS_WAITING_FOR_INITIAL_READY = 1,
|
||||
_HF_RS_WAITING_FOR_READY = 2,
|
||||
_HF_RS_SEND_DATA = 3,
|
||||
} runState_t;
|
||||
|
||||
typedef struct {
|
||||
honggfuzz_t* global;
|
||||
pid_t pid;
|
||||
int64_t timeStartedUSecs;
|
||||
char crashFileName[PATH_MAX];
|
||||
uint64_t pc;
|
||||
uint64_t backtrace;
|
||||
uint64_t access;
|
||||
int exception;
|
||||
char report[_HF_REPORT_SIZE];
|
||||
bool mainWorker;
|
||||
unsigned mutationsPerRun;
|
||||
dynfile_t* dynfile;
|
||||
bool staticFileTryMore;
|
||||
uint32_t fuzzNo;
|
||||
int persistentSock;
|
||||
runState_t runState;
|
||||
bool tmOutSignaled;
|
||||
char* args[_HF_ARGS_MAX + 1];
|
||||
int perThreadCovFeedbackFd;
|
||||
unsigned triesLeft;
|
||||
dynfile_t* current;
|
||||
#if !defined(_HF_ARCH_DARWIN)
|
||||
timer_t timerId;
|
||||
#endif // !defined(_HF_ARCH_DARWIN)
|
||||
hwcnt_t hwCnts;
|
||||
|
||||
struct {
|
||||
/* For Linux code */
|
||||
uint8_t* perfMmapBuf;
|
||||
uint8_t* perfMmapAux;
|
||||
int cpuInstrFd;
|
||||
int cpuBranchFd;
|
||||
int cpuIptBtsFd;
|
||||
} arch_linux;
|
||||
} run_t;
|
||||
|
||||
#endif
|
106
custom_mutators/honggfuzz/input.h
Normal file
106
custom_mutators/honggfuzz/input.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef _HG_INPUT_
|
||||
#define _HG_INPUT_
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef __clang__
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "honggfuzz.h"
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
/*
|
||||
* Go-style defer scoped implementation
|
||||
*
|
||||
* If compiled with clang, use: -fblocks -lBlocksRuntime
|
||||
*
|
||||
* Example of use:
|
||||
*
|
||||
* {
|
||||
* int fd = open(fname, O_RDONLY);
|
||||
* if (fd == -1) {
|
||||
* error(....);
|
||||
* return;
|
||||
* }
|
||||
* defer { close(fd); };
|
||||
* ssize_t sz = read(fd, buf, sizeof(buf));
|
||||
* ...
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STRMERGE(a, b) a##b
|
||||
#define _STRMERGE(a, b) __STRMERGE(a, b)
|
||||
#ifdef __clang__
|
||||
#if __has_extension(blocks)
|
||||
static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
|
||||
(*dfunc)();
|
||||
}
|
||||
|
||||
#define defer \
|
||||
void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
|
||||
__attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
|
||||
|
||||
#else /* __has_extension(blocks) */
|
||||
#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
|
||||
#endif /* __has_extension(blocks) */
|
||||
#else /* !__clang__, e.g.: gcc */
|
||||
|
||||
#define __block
|
||||
#define _DEFER(a, count) \
|
||||
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
|
||||
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
|
||||
__attribute__((unused)); \
|
||||
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
|
||||
#define defer _DEFER(a, __COUNTER__)
|
||||
#endif /* ifdef __clang__ */
|
||||
|
||||
#define HF_MIN(x, y) (x <= y ? x : y)
|
||||
#define HF_MAX(x, y) (x >= y ? x : y)
|
||||
#define ATOMIC_GET
|
||||
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
|
||||
#define HF_ATTR_UNUSED __attribute__((unused))
|
||||
#define util_Malloc(x) malloc(x)
|
||||
|
||||
extern uint8_t * queue_input;
|
||||
extern size_t queue_input_size;
|
||||
extern afl_state_t * afl_struct;
|
||||
|
||||
inline void wmb() { }
|
||||
inline void LOG_F(const char *format, ...) { }
|
||||
static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
|
||||
return min + rand_below(afl_struct, max - min + 1);
|
||||
}
|
||||
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
|
||||
|
||||
static inline const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) {
|
||||
*len = queue_input_size;
|
||||
run->dynfile->data = queue_input;
|
||||
run->dynfile->size = queue_input_size;
|
||||
return queue_input;
|
||||
}
|
||||
static inline void input_setSize(run_t* run, size_t sz) {
|
||||
run->dynfile->size = sz;
|
||||
}
|
||||
static inline void util_turnToPrintable(uint8_t* buf, size_t sz) {
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = buf[i] % 95 + 32;
|
||||
}
|
||||
static inline void util_rndBuf(uint8_t* buf, size_t sz) {
|
||||
if (sz == 0) return;
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = (uint8_t)rand_below(afl_struct, 256);
|
||||
}
|
||||
static inline uint8_t util_rndPrintable() {
|
||||
return 32 + rand_below(afl_struct, 127 - 32);
|
||||
}
|
||||
static inline void util_rndBufPrintable(uint8_t* buf, size_t sz) {
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
buf[i] = util_rndPrintable();
|
||||
}
|
||||
|
||||
#endif
|
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
|
1
custom_mutators/honggfuzz/libhfcommon/log.h
Symbolic link
1
custom_mutators/honggfuzz/libhfcommon/log.h
Symbolic link
@ -0,0 +1 @@
|
||||
common.h
|
1
custom_mutators/honggfuzz/libhfcommon/util.h
Symbolic link
1
custom_mutators/honggfuzz/libhfcommon/util.h
Symbolic link
@ -0,0 +1 @@
|
||||
common.h
|
907
custom_mutators/honggfuzz/mangle.c
Normal file
907
custom_mutators/honggfuzz/mangle.c
Normal file
@ -0,0 +1,907 @@
|
||||
/*
|
||||
*
|
||||
* honggfuzz - run->dynfile->datafer mangling routines
|
||||
* -----------------------------------------
|
||||
*
|
||||
* Author:
|
||||
* Robert Swiecki <swiecki@google.com>
|
||||
*
|
||||
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mangle.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "libhfcommon/common.h"
|
||||
#include "libhfcommon/log.h"
|
||||
#include "libhfcommon/util.h"
|
||||
|
||||
static inline size_t mangle_LenLeft(run_t* run, size_t off) {
|
||||
if (off >= run->dynfile->size) {
|
||||
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
|
||||
}
|
||||
return (run->dynfile->size - off - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
if (max > _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;
|
||||
}
|
||||
|
||||
/* Give 50% chance the the uniform distribution */
|
||||
if (util_rnd64() & 1) {
|
||||
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() */
|
||||
static inline size_t mangle_getOffSet(run_t* run) {
|
||||
return mangle_getLen(run->dynfile->size) - 1;
|
||||
}
|
||||
|
||||
/* Offset which can be equal to the file size */
|
||||
static inline size_t mangle_getOffSetPlus1(run_t* run) {
|
||||
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
|
||||
return mangle_getLen(reqlen) - 1;
|
||||
}
|
||||
|
||||
static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
|
||||
if (off_from >= run->dynfile->size) {
|
||||
return;
|
||||
}
|
||||
if (off_to >= run->dynfile->size) {
|
||||
return;
|
||||
}
|
||||
if (off_from == off_to) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len_from = run->dynfile->size - off_from;
|
||||
len = HF_MIN(len, len_from);
|
||||
|
||||
size_t len_to = run->dynfile->size - off_to;
|
||||
len = HF_MIN(len, len_to);
|
||||
|
||||
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, size_t len, bool printable) {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
size_t maxToCopy = run->dynfile->size - off;
|
||||
if (len > maxToCopy) {
|
||||
len = maxToCopy;
|
||||
}
|
||||
|
||||
memmove(&run->dynfile->data[off], src, 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, bool printable) {
|
||||
if (run->dynfile->size >= run->global->mutate.maxInputSz) {
|
||||
return 0;
|
||||
}
|
||||
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
|
||||
len = run->global->mutate.maxInputSz - run->dynfile->size;
|
||||
}
|
||||
|
||||
input_setSize(run, run->dynfile->size + len);
|
||||
mangle_Move(run, off, off + len, run->dynfile->size);
|
||||
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() & 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 maxlen1 = run->dynfile->size - off1;
|
||||
size_t off2 = mangle_getOffSet(run);
|
||||
size_t maxlen2 = run->dynfile->size - off2;
|
||||
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
|
||||
|
||||
if (off1 == off2) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||
|
||||
/* Use a temp buf, as Insert/Inflate can change source bytes */
|
||||
uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
|
||||
defer {
|
||||
free(tmpbuf);
|
||||
};
|
||||
memmove(tmpbuf, &run->dynfile->data[off], len);
|
||||
|
||||
mangle_UseValue(run, tmpbuf, len, printable);
|
||||
}
|
||||
|
||||
static void mangle_Bytes(run_t* run, bool printable) {
|
||||
uint16_t buf;
|
||||
if (printable) {
|
||||
util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
|
||||
} else {
|
||||
buf = util_rnd64();
|
||||
}
|
||||
|
||||
/* Overwrite with random 1-2-byte values */
|
||||
size_t toCopy = util_rndGet(1, 2);
|
||||
mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
|
||||
}
|
||||
|
||||
static void mangle_ByteRepeat(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);
|
||||
if (util_rnd64() & 0x1) {
|
||||
len = mangle_Inflate(run, destOff, len, printable);
|
||||
}
|
||||
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
|
||||
}
|
||||
|
||||
static void mangle_Bit(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
|
||||
if (printable) {
|
||||
util_turnToPrintable(&(run->dynfile->data[off]), 1);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const uint8_t val[8];
|
||||
const size_t size;
|
||||
} mangleMagicVals[] = {
|
||||
/* 1B - No endianness */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x02\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x03\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x04\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x05\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x06\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x07\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x08\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x09\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x10\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x20\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x40\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\x81\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 1},
|
||||
/* 2B - NE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x01\x01\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x80\x80\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFF\xFF\x00\x00\x00\x00\x00\x00", 2},
|
||||
/* 2B - BE */
|
||||
{"\x00\x01\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x02\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x03\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x04\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x05\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x06\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x07\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x08\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x09\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0A\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0B\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0C\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0D\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0E\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x0F\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x10\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x20\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x40\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x7E\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x7F\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x81\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\xC0\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\xFE\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\xFF\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x7E\xFF\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x7F\xFF\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x80\x01\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFF\xFE\x00\x00\x00\x00\x00\x00", 2},
|
||||
/* 2B - LE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x01\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x02\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x03\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x04\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x05\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x06\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x07\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x08\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x09\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x10\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x20\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x40\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x81\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFF\x7E\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFF\x7F\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\x01\x80\x00\x00\x00\x00\x00\x00", 2},
|
||||
{"\xFE\xFF\x00\x00\x00\x00\x00\x00", 2},
|
||||
/* 4B - NE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x01\x01\x01\x01\x00\x00\x00\x00", 4},
|
||||
{"\x80\x80\x80\x80\x00\x00\x00\x00", 4},
|
||||
{"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", 4},
|
||||
/* 4B - BE */
|
||||
{"\x00\x00\x00\x01\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x02\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x03\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x04\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x05\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x06\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x07\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x08\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x09\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0A\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0B\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0C\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0D\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0E\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x0F\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x10\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x20\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x40\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x7E\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x7F\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x81\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\xC0\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\xFE\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\xFF\x00\x00\x00\x00", 4},
|
||||
{"\x7E\xFF\xFF\xFF\x00\x00\x00\x00", 4},
|
||||
{"\x7F\xFF\xFF\xFF\x00\x00\x00\x00", 4},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x80\x00\x00\x01\x00\x00\x00\x00", 4},
|
||||
{"\xFF\xFF\xFF\xFE\x00\x00\x00\x00", 4},
|
||||
/* 4B - LE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x01\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x02\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x03\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x04\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x05\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x06\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x07\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x08\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x09\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x10\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x20\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x40\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\x81\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 4},
|
||||
{"\xFF\xFF\xFF\x7E\x00\x00\x00\x00", 4},
|
||||
{"\xFF\xFF\xFF\x7F\x00\x00\x00\x00", 4},
|
||||
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
|
||||
{"\x01\x00\x00\x80\x00\x00\x00\x00", 4},
|
||||
{"\xFE\xFF\xFF\xFF\x00\x00\x00\x00", 4},
|
||||
/* 8B - NE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x01\x01\x01\x01\x01\x01\x01\x01", 8},
|
||||
{"\x80\x80\x80\x80\x80\x80\x80\x80", 8},
|
||||
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
|
||||
/* 8B - BE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x01", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x02", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x03", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x04", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x05", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x06", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x07", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x08", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x09", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0A", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0B", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0C", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0D", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0E", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x0F", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x10", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x20", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x40", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x7E", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x7F", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x81", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\xC0", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\xFE", 8},
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\xFF", 8},
|
||||
{"\x7E\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
|
||||
{"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x01", 8},
|
||||
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 8},
|
||||
/* 8B - LE */
|
||||
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x01\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x02\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x03\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x04\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x05\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x06\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x07\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x08\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x09\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x10\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x20\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x40\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\x81\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 8},
|
||||
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7E", 8},
|
||||
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 8},
|
||||
{"\x00\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},
|
||||
};
|
||||
|
||||
static void mangle_Magic(run_t* run, bool printable) {
|
||||
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
|
||||
mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
|
||||
}
|
||||
|
||||
static void mangle_StaticDict(run_t* run, bool printable) {
|
||||
if (run->global->mutate.dictionaryCnt == 0) {
|
||||
mangle_Bytes(run, printable);
|
||||
return;
|
||||
}
|
||||
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
|
||||
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
|
||||
run->global->mutate.dictionary[choice].len, printable);
|
||||
}
|
||||
|
||||
static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
|
||||
if (!run->global->feedback.cmpFeedback) {
|
||||
return NULL;
|
||||
}
|
||||
cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
|
||||
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
|
||||
if (cnt == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (cnt > ARRAYSIZE(cmpf->valArr)) {
|
||||
cnt = ARRAYSIZE(cmpf->valArr);
|
||||
}
|
||||
uint32_t choice = util_rndGet(0, cnt - 1);
|
||||
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
|
||||
if (*len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return cmpf->valArr[choice].val;
|
||||
}
|
||||
|
||||
static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
|
||||
size_t len;
|
||||
const uint8_t* val = mangle_FeedbackDict(run, &len);
|
||||
if (val == NULL) {
|
||||
mangle_Bytes(run, printable);
|
||||
return;
|
||||
}
|
||||
mangle_UseValue(run, val, len, printable);
|
||||
}
|
||||
|
||||
static void mangle_MemSet(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||
int val = 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);
|
||||
}
|
||||
|
||||
static void mangle_MemClr(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
size_t len = mangle_getLen(run->dynfile->size - off);
|
||||
int val = printable ? ' ' : 0;
|
||||
|
||||
if (util_rnd64() & 1) {
|
||||
len = mangle_Inflate(run, off, len, printable);
|
||||
}
|
||||
|
||||
memset(&run->dynfile->data[off], val, len);
|
||||
}
|
||||
|
||||
static void mangle_RandomBuf(run_t* run, 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;
|
||||
|
||||
switch (varLen) {
|
||||
case 1: {
|
||||
run->dynfile->data[off] += delta;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int16_t val;
|
||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||
if (util_rnd64() & 0x1) {
|
||||
val += delta;
|
||||
} else {
|
||||
/* Foreign endianess */
|
||||
val = __builtin_bswap16(val);
|
||||
val += delta;
|
||||
val = __builtin_bswap16(val);
|
||||
}
|
||||
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int32_t val;
|
||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||
if (util_rnd64() & 0x1) {
|
||||
val += delta;
|
||||
} else {
|
||||
/* Foreign endianess */
|
||||
val = __builtin_bswap32(val);
|
||||
val += delta;
|
||||
val = __builtin_bswap32(val);
|
||||
}
|
||||
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int64_t val;
|
||||
memcpy(&val, &run->dynfile->data[off], sizeof(val));
|
||||
if (util_rnd64() & 0x1) {
|
||||
val += delta;
|
||||
} else {
|
||||
/* Foreign endianess */
|
||||
val = __builtin_bswap64(val);
|
||||
val += delta;
|
||||
val = __builtin_bswap64(val);
|
||||
}
|
||||
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_F("Unknown variable length size: %zu", varLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mangle_AddSub(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
|
||||
/* 1,2,4,8 */
|
||||
size_t varLen = 1U << util_rndGet(0, 3);
|
||||
if ((run->dynfile->size - off) < varLen) {
|
||||
varLen = 1;
|
||||
}
|
||||
|
||||
uint64_t range;
|
||||
switch (varLen) {
|
||||
case 1:
|
||||
range = 16;
|
||||
break;
|
||||
case 2:
|
||||
range = 4096;
|
||||
break;
|
||||
case 4:
|
||||
range = 1048576;
|
||||
break;
|
||||
case 8:
|
||||
range = 268435456;
|
||||
break;
|
||||
default:
|
||||
LOG_F("Invalid operand size: %zu", varLen);
|
||||
}
|
||||
|
||||
mangle_AddSubWithRange(run, off, varLen, range, printable);
|
||||
}
|
||||
|
||||
static void mangle_IncByte(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
if (printable) {
|
||||
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
|
||||
} else {
|
||||
run->dynfile->data[off] += (uint8_t)1UL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mangle_DecByte(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
if (printable) {
|
||||
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
|
||||
} else {
|
||||
run->dynfile->data[off] -= (uint8_t)1UL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mangle_NegByte(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
if (printable) {
|
||||
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
|
||||
} else {
|
||||
run->dynfile->data[off] = ~(run->dynfile->data[off]);
|
||||
}
|
||||
}
|
||||
|
||||
static void mangle_Expand(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
size_t len;
|
||||
if (util_rnd64() % 16) {
|
||||
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
|
||||
} else {
|
||||
len = mangle_getLen(run->global->mutate.maxInputSz - off);
|
||||
}
|
||||
|
||||
mangle_Inflate(run, off, len, printable);
|
||||
}
|
||||
|
||||
static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
|
||||
if (run->dynfile->size <= 2U) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t off_start = mangle_getOffSet(run);
|
||||
size_t len = mangle_LenLeft(run, off_start);
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
if (util_rnd64() % 16) {
|
||||
len = mangle_getLen(HF_MIN(16, len));
|
||||
} else {
|
||||
len = mangle_getLen(len);
|
||||
}
|
||||
size_t off_end = off_start + len;
|
||||
size_t len_to_move = run->dynfile->size - off_end;
|
||||
|
||||
mangle_Move(run, off_end, off_start, len_to_move);
|
||||
input_setSize(run, run->dynfile->size - len);
|
||||
}
|
||||
static void mangle_ASCIINum(run_t* run, bool printable) {
|
||||
size_t len = util_rndGet(2, 8);
|
||||
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
|
||||
|
||||
mangle_UseValue(run, (const uint8_t*)buf, len, printable);
|
||||
}
|
||||
|
||||
static void mangle_ASCIINumChange(run_t* run, bool printable) {
|
||||
size_t off = mangle_getOffSet(run);
|
||||
|
||||
/* Find a digit */
|
||||
for (; off < run->dynfile->size; off++) {
|
||||
if (isdigit(run->dynfile->data[off])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t left = run->dynfile->size - off;
|
||||
if (left == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
uint64_t val = 0;
|
||||
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
|
||||
for (len = 0; (len < 20) && (len < left); len++) {
|
||||
char c = run->dynfile->data[off + len];
|
||||
if (!isdigit(c)) {
|
||||
break;
|
||||
}
|
||||
val *= 10;
|
||||
val += (c - '0');
|
||||
}
|
||||
|
||||
switch (util_rndGet(0, 7)) {
|
||||
case 0:
|
||||
val++;
|
||||
break;
|
||||
case 1:
|
||||
val--;
|
||||
break;
|
||||
case 2:
|
||||
val *= 2;
|
||||
break;
|
||||
case 3:
|
||||
val /= 2;
|
||||
break;
|
||||
case 4:
|
||||
val = util_rnd64();
|
||||
break;
|
||||
case 5:
|
||||
val += util_rndGet(1, 256);
|
||||
break;
|
||||
case 6:
|
||||
val -= util_rndGet(1, 256);
|
||||
break;
|
||||
case 7:
|
||||
val = ~(val);
|
||||
break;
|
||||
default:
|
||||
LOG_F("Invalid choice");
|
||||
};
|
||||
|
||||
char buf[20];
|
||||
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) {
|
||||
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
|
||||
mangle_Bytes(run, printable);
|
||||
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 len = mangle_getLen(sz - remoteOff);
|
||||
mangle_UseValue(run, &buf[remoteOff], len, printable);
|
||||
}
|
||||
|
||||
static void mangle_Resize(run_t* run, bool printable) {
|
||||
ssize_t oldsz = run->dynfile->size;
|
||||
ssize_t newsz = 0;
|
||||
|
||||
uint64_t choice = util_rndGet(0, 32);
|
||||
switch (choice) {
|
||||
case 0: /* Set new size arbitrarily */
|
||||
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
|
||||
break;
|
||||
case 1 ... 4: /* Increase size by a small value */
|
||||
newsz = oldsz + (ssize_t)util_rndGet(0, 8);
|
||||
break;
|
||||
case 5: /* Increase size by a larger value */
|
||||
newsz = oldsz + (ssize_t)util_rndGet(9, 128);
|
||||
break;
|
||||
case 6 ... 9: /* Decrease size by a small value */
|
||||
newsz = oldsz - (ssize_t)util_rndGet(0, 8);
|
||||
break;
|
||||
case 10: /* Decrease size by a larger value */
|
||||
newsz = oldsz - (ssize_t)util_rndGet(9, 128);
|
||||
break;
|
||||
case 11 ... 32: /* Do nothing */
|
||||
newsz = oldsz;
|
||||
break;
|
||||
default:
|
||||
LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
|
||||
break;
|
||||
}
|
||||
if (newsz < 1) {
|
||||
newsz = 1;
|
||||
}
|
||||
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
|
||||
newsz = run->global->mutate.maxInputSz;
|
||||
}
|
||||
|
||||
input_setSize(run, (size_t)newsz);
|
||||
if (newsz > oldsz) {
|
||||
if (printable) {
|
||||
memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mangle_mangleContent(run_t* run, int speed_factor) {
|
||||
static void (*const mangleFuncs[])(run_t * run, bool printable) = {
|
||||
mangle_Shrink,
|
||||
mangle_Expand,
|
||||
mangle_Bit,
|
||||
mangle_IncByte,
|
||||
mangle_DecByte,
|
||||
mangle_NegByte,
|
||||
mangle_AddSub,
|
||||
mangle_MemSet,
|
||||
mangle_MemClr,
|
||||
mangle_MemSwap,
|
||||
mangle_MemCopy,
|
||||
mangle_Bytes,
|
||||
mangle_ASCIINum,
|
||||
mangle_ASCIINumChange,
|
||||
mangle_ByteRepeat,
|
||||
mangle_Magic,
|
||||
mangle_StaticDict,
|
||||
mangle_ConstFeedbackDict,
|
||||
mangle_RandomBuf,
|
||||
mangle_Splice,
|
||||
};
|
||||
|
||||
if (run->mutationsPerRun == 0U) {
|
||||
return;
|
||||
}
|
||||
if (run->dynfile->size == 0U) {
|
||||
mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
|
||||
}
|
||||
|
||||
uint64_t changesCnt = run->global->mutate.mutationsPerRun;
|
||||
|
||||
if (speed_factor < 5) {
|
||||
changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
|
||||
} else if (speed_factor < 10) {
|
||||
changesCnt = run->global->mutate.mutationsPerRun;
|
||||
} else {
|
||||
changesCnt = HF_MIN(speed_factor, 10);
|
||||
changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
|
||||
}
|
||||
|
||||
/* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
|
||||
if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
|
||||
if (util_rnd64() & 0x1) {
|
||||
mangle_Splice(run, run->global->cfg.only_printable);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
|
||||
}
|
||||
}
|
||||
|
||||
wmb();
|
||||
}
|
31
custom_mutators/honggfuzz/mangle.h
Normal file
31
custom_mutators/honggfuzz/mangle.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
*
|
||||
* honggfuzz - buffer mangling routines
|
||||
* -----------------------------------------
|
||||
*
|
||||
* Author: Robert Swiecki <swiecki@google.com>
|
||||
*
|
||||
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HF_MANGLE_H_
|
||||
#define _HF_MANGLE_H_
|
||||
|
||||
#include "honggfuzz.h"
|
||||
|
||||
extern void mangle_mangleContent(run_t* run, int speed_factor);
|
||||
|
||||
#endif
|
35
custom_mutators/libfuzzer/FuzzerBuiltins.h
Normal file
35
custom_mutators/libfuzzer/FuzzerBuiltins.h
Normal file
@ -0,0 +1,35 @@
|
||||
//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Wrapper functions and macros around builtin functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_BUILTINS_H
|
||||
#define LLVM_FUZZER_BUILTINS_H
|
||||
|
||||
#include "FuzzerPlatform.h"
|
||||
|
||||
#if !LIBFUZZER_MSVC
|
||||
#include <cstdint>
|
||||
|
||||
#define GET_CALLER_PC() __builtin_return_address(0)
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
|
||||
|
||||
inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
|
||||
inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
|
||||
inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // !LIBFUZZER_MSVC
|
||||
#endif // LLVM_FUZZER_BUILTINS_H
|
72
custom_mutators/libfuzzer/FuzzerBuiltinsMsvc.h
Normal file
72
custom_mutators/libfuzzer/FuzzerBuiltinsMsvc.h
Normal file
@ -0,0 +1,72 @@
|
||||
//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Wrapper functions and macros that use intrinsics instead of builtin functions
|
||||
// which cannot be compiled by MSVC.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_BUILTINS_MSVC_H
|
||||
#define LLVM_FUZZER_BUILTINS_MSVC_H
|
||||
|
||||
#include "FuzzerPlatform.h"
|
||||
|
||||
#if LIBFUZZER_MSVC
|
||||
#include <intrin.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent
|
||||
// from <intrin.h>
|
||||
#define GET_CALLER_PC() _ReturnAddress()
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on
|
||||
// Windows since the builtins are not supported by MSVC.
|
||||
inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
|
||||
|
||||
// The functions below were mostly copied from
|
||||
// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used
|
||||
// outside of Windows.
|
||||
inline uint32_t Clzll(uint64_t X) {
|
||||
unsigned long LeadZeroIdx = 0;
|
||||
|
||||
#if !defined(_M_ARM) && !defined(_M_X64)
|
||||
// Scan the high 32 bits.
|
||||
if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X >> 32)))
|
||||
return static_cast<int>(63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB.
|
||||
// Scan the low 32 bits.
|
||||
if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X)))
|
||||
return static_cast<int>(63 - LeadZeroIdx);
|
||||
|
||||
#else
|
||||
if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
|
||||
#endif
|
||||
return 64;
|
||||
}
|
||||
|
||||
inline uint32_t Clz(uint32_t X) {
|
||||
unsigned long LeadZeroIdx = 0;
|
||||
if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline int Popcountll(unsigned long long X) {
|
||||
#if !defined(_M_ARM) && !defined(_M_X64)
|
||||
return __popcnt(X) + __popcnt(X >> 32);
|
||||
#else
|
||||
return __popcnt64(X);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZER_MSVC
|
||||
#endif // LLVM_FUZZER_BUILTINS_MSVC_H
|
178
custom_mutators/libfuzzer/FuzzerCommand.h
Normal file
178
custom_mutators/libfuzzer/FuzzerCommand.h
Normal file
@ -0,0 +1,178 @@
|
||||
//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FuzzerCommand represents a command to run in a subprocess. It allows callers
|
||||
// to manage command line arguments and output and error streams.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_COMMAND_H
|
||||
#define LLVM_FUZZER_COMMAND_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
class Command final {
|
||||
public:
|
||||
// This command line flag is used to indicate that the remaining command line
|
||||
// is immutable, meaning this flag effectively marks the end of the mutable
|
||||
// argument list.
|
||||
static inline const char *ignoreRemainingArgs() {
|
||||
return "-ignore_remaining_args=1";
|
||||
}
|
||||
|
||||
Command() : CombinedOutAndErr(false) {}
|
||||
|
||||
explicit Command(const Vector<std::string> &ArgsToAdd)
|
||||
: Args(ArgsToAdd), CombinedOutAndErr(false) {}
|
||||
|
||||
explicit Command(const Command &Other)
|
||||
: Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
|
||||
OutputFile(Other.OutputFile) {}
|
||||
|
||||
Command &operator=(const Command &Other) {
|
||||
Args = Other.Args;
|
||||
CombinedOutAndErr = Other.CombinedOutAndErr;
|
||||
OutputFile = Other.OutputFile;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Command() {}
|
||||
|
||||
// Returns true if the given Arg is present in Args. Only checks up to
|
||||
// "-ignore_remaining_args=1".
|
||||
bool hasArgument(const std::string &Arg) const {
|
||||
auto i = endMutableArgs();
|
||||
return std::find(Args.begin(), i, Arg) != i;
|
||||
}
|
||||
|
||||
// Gets all of the current command line arguments, **including** those after
|
||||
// "-ignore-remaining-args=1".
|
||||
const Vector<std::string> &getArguments() const { return Args; }
|
||||
|
||||
// Adds the given argument before "-ignore_remaining_args=1", or at the end
|
||||
// if that flag isn't present.
|
||||
void addArgument(const std::string &Arg) {
|
||||
Args.insert(endMutableArgs(), Arg);
|
||||
}
|
||||
|
||||
// Adds all given arguments before "-ignore_remaining_args=1", or at the end
|
||||
// if that flag isn't present.
|
||||
void addArguments(const Vector<std::string> &ArgsToAdd) {
|
||||
Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
|
||||
}
|
||||
|
||||
// Removes the given argument from the command argument list. Ignores any
|
||||
// occurrences after "-ignore_remaining_args=1", if present.
|
||||
void removeArgument(const std::string &Arg) {
|
||||
auto i = endMutableArgs();
|
||||
Args.erase(std::remove(Args.begin(), i, Arg), i);
|
||||
}
|
||||
|
||||
// Like hasArgument, but checks for "-[Flag]=...".
|
||||
bool hasFlag(const std::string &Flag) const {
|
||||
std::string Arg("-" + Flag + "=");
|
||||
auto IsMatch = [&](const std::string &Other) {
|
||||
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
|
||||
};
|
||||
return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
|
||||
}
|
||||
|
||||
// Returns the value of the first instance of a given flag, or an empty string
|
||||
// if the flag isn't present. Ignores any occurrences after
|
||||
// "-ignore_remaining_args=1", if present.
|
||||
std::string getFlagValue(const std::string &Flag) const {
|
||||
std::string Arg("-" + Flag + "=");
|
||||
auto IsMatch = [&](const std::string &Other) {
|
||||
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
|
||||
};
|
||||
auto i = endMutableArgs();
|
||||
auto j = std::find_if(Args.begin(), i, IsMatch);
|
||||
std::string result;
|
||||
if (j != i) {
|
||||
result = j->substr(Arg.length());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Like AddArgument, but adds "-[Flag]=[Value]".
|
||||
void addFlag(const std::string &Flag, const std::string &Value) {
|
||||
addArgument("-" + Flag + "=" + Value);
|
||||
}
|
||||
|
||||
// Like RemoveArgument, but removes "-[Flag]=...".
|
||||
void removeFlag(const std::string &Flag) {
|
||||
std::string Arg("-" + Flag + "=");
|
||||
auto IsMatch = [&](const std::string &Other) {
|
||||
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
|
||||
};
|
||||
auto i = endMutableArgs();
|
||||
Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
|
||||
}
|
||||
|
||||
// Returns whether the command's stdout is being written to an output file.
|
||||
bool hasOutputFile() const { return !OutputFile.empty(); }
|
||||
|
||||
// Returns the currently set output file.
|
||||
const std::string &getOutputFile() const { return OutputFile; }
|
||||
|
||||
// Configures the command to redirect its output to the name file.
|
||||
void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
|
||||
|
||||
// Returns whether the command's stderr is redirected to stdout.
|
||||
bool isOutAndErrCombined() const { return CombinedOutAndErr; }
|
||||
|
||||
// Sets whether to redirect the command's stderr to its stdout.
|
||||
void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
|
||||
|
||||
// Returns a string representation of the command. On many systems this will
|
||||
// be the equivalent command line.
|
||||
std::string toString() const {
|
||||
std::stringstream SS;
|
||||
for (auto arg : getArguments())
|
||||
SS << arg << " ";
|
||||
if (hasOutputFile())
|
||||
SS << ">" << getOutputFile() << " ";
|
||||
if (isOutAndErrCombined())
|
||||
SS << "2>&1 ";
|
||||
std::string result = SS.str();
|
||||
if (!result.empty())
|
||||
result = result.substr(0, result.length() - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
Command(Command &&Other) = delete;
|
||||
Command &operator=(Command &&Other) = delete;
|
||||
|
||||
Vector<std::string>::iterator endMutableArgs() {
|
||||
return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
|
||||
}
|
||||
|
||||
Vector<std::string>::const_iterator endMutableArgs() const {
|
||||
return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
|
||||
}
|
||||
|
||||
// The command arguments. Args[0] is the command name.
|
||||
Vector<std::string> Args;
|
||||
|
||||
// True indicates stderr is redirected to stdout.
|
||||
bool CombinedOutAndErr;
|
||||
|
||||
// If not empty, stdout is redirected to the named file.
|
||||
std::string OutputFile;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_COMMAND_H
|
581
custom_mutators/libfuzzer/FuzzerCorpus.h
Normal file
581
custom_mutators/libfuzzer/FuzzerCorpus.h
Normal file
@ -0,0 +1,581 @@
|
||||
//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::InputCorpus
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_CORPUS
|
||||
#define LLVM_FUZZER_CORPUS
|
||||
|
||||
#include "FuzzerDataFlowTrace.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct InputInfo {
|
||||
Unit U; // The actual input data.
|
||||
std::chrono::microseconds TimeOfUnit;
|
||||
uint8_t Sha1[kSHA1NumBytes]; // Checksum.
|
||||
// Number of features that this input has and no smaller input has.
|
||||
size_t NumFeatures = 0;
|
||||
size_t Tmp = 0; // Used by ValidateFeatureSet.
|
||||
// Stats.
|
||||
size_t NumExecutedMutations = 0;
|
||||
size_t NumSuccessfullMutations = 0;
|
||||
bool NeverReduce = false;
|
||||
bool MayDeleteFile = false;
|
||||
bool Reduced = false;
|
||||
bool HasFocusFunction = false;
|
||||
Vector<uint32_t> UniqFeatureSet;
|
||||
Vector<uint8_t> DataFlowTraceForFocusFunction;
|
||||
// Power schedule.
|
||||
bool NeedsEnergyUpdate = false;
|
||||
double Energy = 0.0;
|
||||
size_t SumIncidence = 0;
|
||||
Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs;
|
||||
|
||||
// Delete feature Idx and its frequency from FeatureFreqs.
|
||||
bool DeleteFeatureFreq(uint32_t Idx) {
|
||||
if (FeatureFreqs.empty())
|
||||
return false;
|
||||
|
||||
// Binary search over local feature frequencies sorted by index.
|
||||
auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
|
||||
std::pair<uint32_t, uint16_t>(Idx, 0));
|
||||
|
||||
if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
|
||||
FeatureFreqs.erase(Lower);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign more energy to a high-entropy seed, i.e., that reveals more
|
||||
// information about the globally rare features in the neighborhood of the
|
||||
// seed. Since we do not know the entropy of a seed that has never been
|
||||
// executed we assign fresh seeds maximum entropy and let II->Energy approach
|
||||
// the true entropy from above. If ScalePerExecTime is true, the computed
|
||||
// entropy is scaled based on how fast this input executes compared to the
|
||||
// average execution time of inputs. The faster an input executes, the more
|
||||
// energy gets assigned to the input.
|
||||
void UpdateEnergy(size_t GlobalNumberOfFeatures, bool ScalePerExecTime,
|
||||
std::chrono::microseconds AverageUnitExecutionTime) {
|
||||
Energy = 0.0;
|
||||
SumIncidence = 0;
|
||||
|
||||
// Apply add-one smoothing to locally discovered features.
|
||||
for (auto F : FeatureFreqs) {
|
||||
size_t LocalIncidence = F.second + 1;
|
||||
Energy -= LocalIncidence * logl(LocalIncidence);
|
||||
SumIncidence += LocalIncidence;
|
||||
}
|
||||
|
||||
// Apply add-one smoothing to locally undiscovered features.
|
||||
// PreciseEnergy -= 0; // since logl(1.0) == 0)
|
||||
SumIncidence += (GlobalNumberOfFeatures - FeatureFreqs.size());
|
||||
|
||||
// Add a single locally abundant feature apply add-one smoothing.
|
||||
size_t AbdIncidence = NumExecutedMutations + 1;
|
||||
Energy -= AbdIncidence * logl(AbdIncidence);
|
||||
SumIncidence += AbdIncidence;
|
||||
|
||||
// Normalize.
|
||||
if (SumIncidence != 0)
|
||||
Energy = (Energy / SumIncidence) + logl(SumIncidence);
|
||||
|
||||
if (ScalePerExecTime) {
|
||||
// Scaling to favor inputs with lower execution time.
|
||||
uint32_t PerfScore = 100;
|
||||
if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 10)
|
||||
PerfScore = 10;
|
||||
else if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 4)
|
||||
PerfScore = 25;
|
||||
else if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 2)
|
||||
PerfScore = 50;
|
||||
else if (TimeOfUnit.count() * 3 > AverageUnitExecutionTime.count() * 4)
|
||||
PerfScore = 75;
|
||||
else if (TimeOfUnit.count() * 4 < AverageUnitExecutionTime.count())
|
||||
PerfScore = 300;
|
||||
else if (TimeOfUnit.count() * 3 < AverageUnitExecutionTime.count())
|
||||
PerfScore = 200;
|
||||
else if (TimeOfUnit.count() * 2 < AverageUnitExecutionTime.count())
|
||||
PerfScore = 150;
|
||||
|
||||
Energy *= PerfScore;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the frequency of the feature Idx.
|
||||
void UpdateFeatureFrequency(uint32_t Idx) {
|
||||
NeedsEnergyUpdate = true;
|
||||
|
||||
// The local feature frequencies is an ordered vector of pairs.
|
||||
// If there are no local feature frequencies, push_back preserves order.
|
||||
// Set the feature frequency for feature Idx32 to 1.
|
||||
if (FeatureFreqs.empty()) {
|
||||
FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(Idx, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
// Binary search over local feature frequencies sorted by index.
|
||||
auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
|
||||
std::pair<uint32_t, uint16_t>(Idx, 0));
|
||||
|
||||
// If feature Idx32 already exists, increment its frequency.
|
||||
// Otherwise, insert a new pair right after the next lower index.
|
||||
if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
|
||||
Lower->second++;
|
||||
} else {
|
||||
FeatureFreqs.insert(Lower, std::pair<uint32_t, uint16_t>(Idx, 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct EntropicOptions {
|
||||
bool Enabled;
|
||||
size_t NumberOfRarestFeatures;
|
||||
size_t FeatureFrequencyThreshold;
|
||||
bool ScalePerExecTime;
|
||||
};
|
||||
|
||||
class InputCorpus {
|
||||
static const uint32_t kFeatureSetSize = 1 << 21;
|
||||
static const uint8_t kMaxMutationFactor = 20;
|
||||
static const size_t kSparseEnergyUpdates = 100;
|
||||
|
||||
size_t NumExecutedMutations = 0;
|
||||
|
||||
EntropicOptions Entropic;
|
||||
|
||||
public:
|
||||
InputCorpus(const std::string &OutputCorpus, EntropicOptions Entropic)
|
||||
: Entropic(Entropic), OutputCorpus(OutputCorpus) {
|
||||
memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
|
||||
memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
|
||||
}
|
||||
~InputCorpus() {
|
||||
for (auto II : Inputs)
|
||||
delete II;
|
||||
}
|
||||
size_t size() const { return Inputs.size(); }
|
||||
size_t SizeInBytes() const {
|
||||
size_t Res = 0;
|
||||
for (auto II : Inputs)
|
||||
Res += II->U.size();
|
||||
return Res;
|
||||
}
|
||||
size_t NumActiveUnits() const {
|
||||
size_t Res = 0;
|
||||
for (auto II : Inputs)
|
||||
Res += !II->U.empty();
|
||||
return Res;
|
||||
}
|
||||
size_t MaxInputSize() const {
|
||||
size_t Res = 0;
|
||||
for (auto II : Inputs)
|
||||
Res = std::max(Res, II->U.size());
|
||||
return Res;
|
||||
}
|
||||
void IncrementNumExecutedMutations() { NumExecutedMutations++; }
|
||||
|
||||
size_t NumInputsThatTouchFocusFunction() {
|
||||
return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
|
||||
return II->HasFocusFunction;
|
||||
});
|
||||
}
|
||||
|
||||
size_t NumInputsWithDataFlowTrace() {
|
||||
return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
|
||||
return !II->DataFlowTraceForFocusFunction.empty();
|
||||
});
|
||||
}
|
||||
|
||||
bool empty() const { return Inputs.empty(); }
|
||||
const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
|
||||
InputInfo *AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
|
||||
bool HasFocusFunction, bool NeverReduce,
|
||||
std::chrono::microseconds TimeOfUnit,
|
||||
const Vector<uint32_t> &FeatureSet,
|
||||
const DataFlowTrace &DFT, const InputInfo *BaseII) {
|
||||
assert(!U.empty());
|
||||
if (FeatureDebug)
|
||||
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
|
||||
Inputs.push_back(new InputInfo());
|
||||
InputInfo &II = *Inputs.back();
|
||||
II.U = U;
|
||||
II.NumFeatures = NumFeatures;
|
||||
II.NeverReduce = NeverReduce;
|
||||
II.TimeOfUnit = TimeOfUnit;
|
||||
II.MayDeleteFile = MayDeleteFile;
|
||||
II.UniqFeatureSet = FeatureSet;
|
||||
II.HasFocusFunction = HasFocusFunction;
|
||||
// Assign maximal energy to the new seed.
|
||||
II.Energy = RareFeatures.empty() ? 1.0 : log(RareFeatures.size());
|
||||
II.SumIncidence = RareFeatures.size();
|
||||
II.NeedsEnergyUpdate = false;
|
||||
std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
|
||||
ComputeSHA1(U.data(), U.size(), II.Sha1);
|
||||
auto Sha1Str = Sha1ToString(II.Sha1);
|
||||
Hashes.insert(Sha1Str);
|
||||
if (HasFocusFunction)
|
||||
if (auto V = DFT.Get(Sha1Str))
|
||||
II.DataFlowTraceForFocusFunction = *V;
|
||||
// This is a gross heuristic.
|
||||
// Ideally, when we add an element to a corpus we need to know its DFT.
|
||||
// But if we don't, we'll use the DFT of its base input.
|
||||
if (II.DataFlowTraceForFocusFunction.empty() && BaseII)
|
||||
II.DataFlowTraceForFocusFunction = BaseII->DataFlowTraceForFocusFunction;
|
||||
DistributionNeedsUpdate = true;
|
||||
PrintCorpus();
|
||||
// ValidateFeatureSet();
|
||||
return &II;
|
||||
}
|
||||
|
||||
// Debug-only
|
||||
void PrintUnit(const Unit &U) {
|
||||
if (!FeatureDebug) return;
|
||||
for (uint8_t C : U) {
|
||||
if (C != 'F' && C != 'U' && C != 'Z')
|
||||
C = '.';
|
||||
Printf("%c", C);
|
||||
}
|
||||
}
|
||||
|
||||
// Debug-only
|
||||
void PrintFeatureSet(const Vector<uint32_t> &FeatureSet) {
|
||||
if (!FeatureDebug) return;
|
||||
Printf("{");
|
||||
for (uint32_t Feature: FeatureSet)
|
||||
Printf("%u,", Feature);
|
||||
Printf("}");
|
||||
}
|
||||
|
||||
// Debug-only
|
||||
void PrintCorpus() {
|
||||
if (!FeatureDebug) return;
|
||||
Printf("======= CORPUS:\n");
|
||||
int i = 0;
|
||||
for (auto II : Inputs) {
|
||||
if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) {
|
||||
Printf("[%2d] ", i);
|
||||
Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size());
|
||||
PrintUnit(II->U);
|
||||
Printf(" ");
|
||||
PrintFeatureSet(II->UniqFeatureSet);
|
||||
Printf("\n");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Replace(InputInfo *II, const Unit &U) {
|
||||
assert(II->U.size() > U.size());
|
||||
Hashes.erase(Sha1ToString(II->Sha1));
|
||||
DeleteFile(*II);
|
||||
ComputeSHA1(U.data(), U.size(), II->Sha1);
|
||||
Hashes.insert(Sha1ToString(II->Sha1));
|
||||
II->U = U;
|
||||
II->Reduced = true;
|
||||
DistributionNeedsUpdate = true;
|
||||
}
|
||||
|
||||
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
|
||||
bool HasUnit(const std::string &H) { return Hashes.count(H); }
|
||||
InputInfo &ChooseUnitToMutate(Random &Rand) {
|
||||
InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
|
||||
assert(!II.U.empty());
|
||||
return II;
|
||||
}
|
||||
|
||||
InputInfo &ChooseUnitToCrossOverWith(Random &Rand, bool UniformDist) {
|
||||
if (!UniformDist) {
|
||||
return ChooseUnitToMutate(Rand);
|
||||
}
|
||||
InputInfo &II = *Inputs[Rand(Inputs.size())];
|
||||
assert(!II.U.empty());
|
||||
return II;
|
||||
}
|
||||
|
||||
// Returns an index of random unit from the corpus to mutate.
|
||||
size_t ChooseUnitIdxToMutate(Random &Rand) {
|
||||
UpdateCorpusDistribution(Rand);
|
||||
size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
|
||||
assert(Idx < Inputs.size());
|
||||
return Idx;
|
||||
}
|
||||
|
||||
void PrintStats() {
|
||||
for (size_t i = 0; i < Inputs.size(); i++) {
|
||||
const auto &II = *Inputs[i];
|
||||
Printf(" [% 3zd %s] sz: % 5zd runs: % 5zd succ: % 5zd focus: %d\n", i,
|
||||
Sha1ToString(II.Sha1).c_str(), II.U.size(),
|
||||
II.NumExecutedMutations, II.NumSuccessfullMutations, II.HasFocusFunction);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintFeatureSet() {
|
||||
for (size_t i = 0; i < kFeatureSetSize; i++) {
|
||||
if(size_t Sz = GetFeature(i))
|
||||
Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
|
||||
}
|
||||
Printf("\n\t");
|
||||
for (size_t i = 0; i < Inputs.size(); i++)
|
||||
if (size_t N = Inputs[i]->NumFeatures)
|
||||
Printf(" %zd=>%zd ", i, N);
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
void DeleteFile(const InputInfo &II) {
|
||||
if (!OutputCorpus.empty() && II.MayDeleteFile)
|
||||
RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
|
||||
}
|
||||
|
||||
void DeleteInput(size_t Idx) {
|
||||
InputInfo &II = *Inputs[Idx];
|
||||
DeleteFile(II);
|
||||
Unit().swap(II.U);
|
||||
II.Energy = 0.0;
|
||||
II.NeedsEnergyUpdate = false;
|
||||
DistributionNeedsUpdate = true;
|
||||
if (FeatureDebug)
|
||||
Printf("EVICTED %zd\n", Idx);
|
||||
}
|
||||
|
||||
void AddRareFeature(uint32_t Idx) {
|
||||
// Maintain *at least* TopXRarestFeatures many rare features
|
||||
// and all features with a frequency below ConsideredRare.
|
||||
// Remove all other features.
|
||||
while (RareFeatures.size() > Entropic.NumberOfRarestFeatures &&
|
||||
FreqOfMostAbundantRareFeature > Entropic.FeatureFrequencyThreshold) {
|
||||
|
||||
// Find most and second most abbundant feature.
|
||||
uint32_t MostAbundantRareFeatureIndices[2] = {RareFeatures[0],
|
||||
RareFeatures[0]};
|
||||
size_t Delete = 0;
|
||||
for (size_t i = 0; i < RareFeatures.size(); i++) {
|
||||
uint32_t Idx2 = RareFeatures[i];
|
||||
if (GlobalFeatureFreqs[Idx2] >=
|
||||
GlobalFeatureFreqs[MostAbundantRareFeatureIndices[0]]) {
|
||||
MostAbundantRareFeatureIndices[1] = MostAbundantRareFeatureIndices[0];
|
||||
MostAbundantRareFeatureIndices[0] = Idx2;
|
||||
Delete = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove most abundant rare feature.
|
||||
RareFeatures[Delete] = RareFeatures.back();
|
||||
RareFeatures.pop_back();
|
||||
|
||||
for (auto II : Inputs) {
|
||||
if (II->DeleteFeatureFreq(MostAbundantRareFeatureIndices[0]))
|
||||
II->NeedsEnergyUpdate = true;
|
||||
}
|
||||
|
||||
// Set 2nd most abundant as the new most abundant feature count.
|
||||
FreqOfMostAbundantRareFeature =
|
||||
GlobalFeatureFreqs[MostAbundantRareFeatureIndices[1]];
|
||||
}
|
||||
|
||||
// Add rare feature, handle collisions, and update energy.
|
||||
RareFeatures.push_back(Idx);
|
||||
GlobalFeatureFreqs[Idx] = 0;
|
||||
for (auto II : Inputs) {
|
||||
II->DeleteFeatureFreq(Idx);
|
||||
|
||||
// Apply add-one smoothing to this locally undiscovered feature.
|
||||
// Zero energy seeds will never be fuzzed and remain zero energy.
|
||||
if (II->Energy > 0.0) {
|
||||
II->SumIncidence += 1;
|
||||
II->Energy += logl(II->SumIncidence) / II->SumIncidence;
|
||||
}
|
||||
}
|
||||
|
||||
DistributionNeedsUpdate = true;
|
||||
}
|
||||
|
||||
bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
|
||||
assert(NewSize);
|
||||
Idx = Idx % kFeatureSetSize;
|
||||
uint32_t OldSize = GetFeature(Idx);
|
||||
if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
|
||||
if (OldSize > 0) {
|
||||
size_t OldIdx = SmallestElementPerFeature[Idx];
|
||||
InputInfo &II = *Inputs[OldIdx];
|
||||
assert(II.NumFeatures > 0);
|
||||
II.NumFeatures--;
|
||||
if (II.NumFeatures == 0)
|
||||
DeleteInput(OldIdx);
|
||||
} else {
|
||||
NumAddedFeatures++;
|
||||
if (Entropic.Enabled)
|
||||
AddRareFeature((uint32_t)Idx);
|
||||
}
|
||||
NumUpdatedFeatures++;
|
||||
if (FeatureDebug)
|
||||
Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
|
||||
SmallestElementPerFeature[Idx] = Inputs.size();
|
||||
InputSizesPerFeature[Idx] = NewSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increment frequency of feature Idx globally and locally.
|
||||
void UpdateFeatureFrequency(InputInfo *II, size_t Idx) {
|
||||
uint32_t Idx32 = Idx % kFeatureSetSize;
|
||||
|
||||
// Saturated increment.
|
||||
if (GlobalFeatureFreqs[Idx32] == 0xFFFF)
|
||||
return;
|
||||
uint16_t Freq = GlobalFeatureFreqs[Idx32]++;
|
||||
|
||||
// Skip if abundant.
|
||||
if (Freq > FreqOfMostAbundantRareFeature ||
|
||||
std::find(RareFeatures.begin(), RareFeatures.end(), Idx32) ==
|
||||
RareFeatures.end())
|
||||
return;
|
||||
|
||||
// Update global frequencies.
|
||||
if (Freq == FreqOfMostAbundantRareFeature)
|
||||
FreqOfMostAbundantRareFeature++;
|
||||
|
||||
// Update local frequencies.
|
||||
if (II)
|
||||
II->UpdateFeatureFrequency(Idx32);
|
||||
}
|
||||
|
||||
size_t NumFeatures() const { return NumAddedFeatures; }
|
||||
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
|
||||
|
||||
private:
|
||||
|
||||
static const bool FeatureDebug = false;
|
||||
|
||||
size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
|
||||
|
||||
void ValidateFeatureSet() {
|
||||
if (FeatureDebug)
|
||||
PrintFeatureSet();
|
||||
for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
|
||||
if (GetFeature(Idx))
|
||||
Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
|
||||
for (auto II: Inputs) {
|
||||
if (II->Tmp != II->NumFeatures)
|
||||
Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
|
||||
assert(II->Tmp == II->NumFeatures);
|
||||
II->Tmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the probability distribution for the units in the corpus.
|
||||
// Must be called whenever the corpus or unit weights are changed.
|
||||
//
|
||||
// Hypothesis: inputs that maximize information about globally rare features
|
||||
// are interesting.
|
||||
void UpdateCorpusDistribution(Random &Rand) {
|
||||
// Skip update if no seeds or rare features were added/deleted.
|
||||
// Sparse updates for local change of feature frequencies,
|
||||
// i.e., randomly do not skip.
|
||||
if (!DistributionNeedsUpdate &&
|
||||
(!Entropic.Enabled || Rand(kSparseEnergyUpdates)))
|
||||
return;
|
||||
|
||||
DistributionNeedsUpdate = false;
|
||||
|
||||
size_t N = Inputs.size();
|
||||
assert(N);
|
||||
Intervals.resize(N + 1);
|
||||
Weights.resize(N);
|
||||
std::iota(Intervals.begin(), Intervals.end(), 0);
|
||||
|
||||
std::chrono::microseconds AverageUnitExecutionTime(0);
|
||||
for (auto II : Inputs) {
|
||||
AverageUnitExecutionTime += II->TimeOfUnit;
|
||||
}
|
||||
AverageUnitExecutionTime /= N;
|
||||
|
||||
bool VanillaSchedule = true;
|
||||
if (Entropic.Enabled) {
|
||||
for (auto II : Inputs) {
|
||||
if (II->NeedsEnergyUpdate && II->Energy != 0.0) {
|
||||
II->NeedsEnergyUpdate = false;
|
||||
II->UpdateEnergy(RareFeatures.size(), Entropic.ScalePerExecTime,
|
||||
AverageUnitExecutionTime);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
|
||||
if (Inputs[i]->NumFeatures == 0) {
|
||||
// If the seed doesn't represent any features, assign zero energy.
|
||||
Weights[i] = 0.;
|
||||
} else if (Inputs[i]->NumExecutedMutations / kMaxMutationFactor >
|
||||
NumExecutedMutations / Inputs.size()) {
|
||||
// If the seed was fuzzed a lot more than average, assign zero energy.
|
||||
Weights[i] = 0.;
|
||||
} else {
|
||||
// Otherwise, simply assign the computed energy.
|
||||
Weights[i] = Inputs[i]->Energy;
|
||||
}
|
||||
|
||||
// If energy for all seeds is zero, fall back to vanilla schedule.
|
||||
if (Weights[i] > 0.0)
|
||||
VanillaSchedule = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (VanillaSchedule) {
|
||||
for (size_t i = 0; i < N; i++)
|
||||
Weights[i] = Inputs[i]->NumFeatures
|
||||
? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000 : 1)
|
||||
: 0.;
|
||||
}
|
||||
|
||||
if (FeatureDebug) {
|
||||
for (size_t i = 0; i < N; i++)
|
||||
Printf("%zd ", Inputs[i]->NumFeatures);
|
||||
Printf("SCORE\n");
|
||||
for (size_t i = 0; i < N; i++)
|
||||
Printf("%f ", Weights[i]);
|
||||
Printf("Weights\n");
|
||||
}
|
||||
CorpusDistribution = std::piecewise_constant_distribution<double>(
|
||||
Intervals.begin(), Intervals.end(), Weights.begin());
|
||||
}
|
||||
std::piecewise_constant_distribution<double> CorpusDistribution;
|
||||
|
||||
Vector<double> Intervals;
|
||||
Vector<double> Weights;
|
||||
|
||||
std::unordered_set<std::string> Hashes;
|
||||
Vector<InputInfo*> Inputs;
|
||||
|
||||
size_t NumAddedFeatures = 0;
|
||||
size_t NumUpdatedFeatures = 0;
|
||||
uint32_t InputSizesPerFeature[kFeatureSetSize];
|
||||
uint32_t SmallestElementPerFeature[kFeatureSetSize];
|
||||
|
||||
bool DistributionNeedsUpdate = true;
|
||||
uint16_t FreqOfMostAbundantRareFeature = 0;
|
||||
uint16_t GlobalFeatureFreqs[kFeatureSetSize] = {};
|
||||
Vector<uint32_t> RareFeatures;
|
||||
|
||||
std::string OutputCorpus;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_CORPUS
|
60
custom_mutators/libfuzzer/FuzzerCrossOver.cpp
Normal file
60
custom_mutators/libfuzzer/FuzzerCrossOver.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Cross over test inputs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
|
||||
size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
|
||||
const uint8_t *Data2, size_t Size2,
|
||||
uint8_t *Out, size_t MaxOutSize) {
|
||||
|
||||
assert(Size1 || Size2);
|
||||
MaxOutSize = Rand(MaxOutSize) + 1;
|
||||
size_t OutPos = 0;
|
||||
size_t Pos1 = 0;
|
||||
size_t Pos2 = 0;
|
||||
size_t * InPos = &Pos1;
|
||||
size_t InSize = Size1;
|
||||
const uint8_t *Data = Data1;
|
||||
bool CurrentlyUsingFirstData = true;
|
||||
while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
|
||||
|
||||
// Merge a part of Data into Out.
|
||||
size_t OutSizeLeft = MaxOutSize - OutPos;
|
||||
if (*InPos < InSize) {
|
||||
|
||||
size_t InSizeLeft = InSize - *InPos;
|
||||
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
|
||||
size_t ExtraSize = Rand(MaxExtraSize) + 1;
|
||||
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
|
||||
OutPos += ExtraSize;
|
||||
(*InPos) += ExtraSize;
|
||||
|
||||
}
|
||||
|
||||
// Use the other input data on the next iteration.
|
||||
InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
|
||||
InSize = CurrentlyUsingFirstData ? Size2 : Size1;
|
||||
Data = CurrentlyUsingFirstData ? Data2 : Data1;
|
||||
CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
|
||||
|
||||
}
|
||||
|
||||
return OutPos;
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
344
custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp
Normal file
344
custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp
Normal file
@ -0,0 +1,344 @@
|
||||
//===- FuzzerDataFlowTrace.cpp - DataFlowTrace ---*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::DataFlowTrace
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDataFlowTrace.h"
|
||||
|
||||
#include "FuzzerCommand.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static const char *kFunctionsTxt = "functions.txt";
|
||||
|
||||
bool BlockCoverage::AppendCoverage(const std::string &S) {
|
||||
|
||||
std::stringstream SS(S);
|
||||
return AppendCoverage(SS);
|
||||
|
||||
}
|
||||
|
||||
// Coverage lines have this form:
|
||||
// CN X Y Z T
|
||||
// where N is the number of the function, T is the total number of instrumented
|
||||
// BBs, and X,Y,Z, if present, are the indecies of covered BB.
|
||||
// BB #0, which is the entry block, is not explicitly listed.
|
||||
bool BlockCoverage::AppendCoverage(std::istream &IN) {
|
||||
|
||||
std::string L;
|
||||
while (std::getline(IN, L, '\n')) {
|
||||
|
||||
if (L.empty()) continue;
|
||||
std::stringstream SS(L.c_str() + 1);
|
||||
size_t FunctionId = 0;
|
||||
SS >> FunctionId;
|
||||
if (L[0] == 'F') {
|
||||
|
||||
FunctionsWithDFT.insert(FunctionId);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (L[0] != 'C') continue;
|
||||
Vector<uint32_t> CoveredBlocks;
|
||||
while (true) {
|
||||
|
||||
uint32_t BB = 0;
|
||||
SS >> BB;
|
||||
if (!SS) break;
|
||||
CoveredBlocks.push_back(BB);
|
||||
|
||||
}
|
||||
|
||||
if (CoveredBlocks.empty()) return false;
|
||||
uint32_t NumBlocks = CoveredBlocks.back();
|
||||
CoveredBlocks.pop_back();
|
||||
for (auto BB : CoveredBlocks)
|
||||
if (BB >= NumBlocks) return false;
|
||||
auto It = Functions.find(FunctionId);
|
||||
auto &Counters =
|
||||
It == Functions.end()
|
||||
? Functions.insert({FunctionId, Vector<uint32_t>(NumBlocks)})
|
||||
.first->second
|
||||
: It->second;
|
||||
|
||||
if (Counters.size() != NumBlocks) return false; // wrong number of blocks.
|
||||
|
||||
Counters[0]++;
|
||||
for (auto BB : CoveredBlocks)
|
||||
Counters[BB]++;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Assign weights to each function.
|
||||
// General principles:
|
||||
// * any uncovered function gets weight 0.
|
||||
// * a function with lots of uncovered blocks gets bigger weight.
|
||||
// * a function with a less frequently executed code gets bigger weight.
|
||||
Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {
|
||||
|
||||
Vector<double> Res(NumFunctions);
|
||||
for (auto It : Functions) {
|
||||
|
||||
auto FunctionID = It.first;
|
||||
auto Counters = It.second;
|
||||
assert(FunctionID < NumFunctions);
|
||||
auto &Weight = Res[FunctionID];
|
||||
// Give higher weight if the function has a DFT.
|
||||
Weight = FunctionsWithDFT.count(FunctionID) ? 1000. : 1;
|
||||
// Give higher weight to functions with less frequently seen basic blocks.
|
||||
Weight /= SmallestNonZeroCounter(Counters);
|
||||
// Give higher weight to functions with the most uncovered basic blocks.
|
||||
Weight *= NumberOfUncoveredBlocks(Counters) + 1;
|
||||
|
||||
}
|
||||
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
|
||||
|
||||
Vector<SizedFile> Files;
|
||||
GetSizedFilesFromDir(DirPath, &Files);
|
||||
for (auto &SF : Files) {
|
||||
|
||||
auto Name = Basename(SF.File);
|
||||
if (Name == kFunctionsTxt) continue;
|
||||
if (!CorporaHashes.count(Name)) continue;
|
||||
std::ifstream IF(SF.File);
|
||||
Coverage.AppendCoverage(IF);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void DFTStringAppendToVector(Vector<uint8_t> * DFT,
|
||||
const std::string &DFTString) {
|
||||
|
||||
assert(DFT->size() == DFTString.size());
|
||||
for (size_t I = 0, Len = DFT->size(); I < Len; I++)
|
||||
(*DFT)[I] = DFTString[I] == '1';
|
||||
|
||||
}
|
||||
|
||||
// converts a string of '0' and '1' into a Vector<uint8_t>
|
||||
static Vector<uint8_t> DFTStringToVector(const std::string &DFTString) {
|
||||
|
||||
Vector<uint8_t> DFT(DFTString.size());
|
||||
DFTStringAppendToVector(&DFT, DFTString);
|
||||
return DFT;
|
||||
|
||||
}
|
||||
|
||||
static bool ParseError(const char *Err, const std::string &Line) {
|
||||
|
||||
Printf("DataFlowTrace: parse error: %s: Line: %s\n", Err, Line.c_str());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// TODO(metzman): replace std::string with std::string_view for
|
||||
// better performance. Need to figure our how to use string_view on Windows.
|
||||
static bool ParseDFTLine(const std::string &Line, size_t *FunctionNum,
|
||||
std::string *DFTString) {
|
||||
|
||||
if (!Line.empty() && Line[0] != 'F') return false; // Ignore coverage.
|
||||
size_t SpacePos = Line.find(' ');
|
||||
if (SpacePos == std::string::npos)
|
||||
return ParseError("no space in the trace line", Line);
|
||||
if (Line.empty() || Line[0] != 'F')
|
||||
return ParseError("the trace line doesn't start with 'F'", Line);
|
||||
*FunctionNum = std::atol(Line.c_str() + 1);
|
||||
const char *Beg = Line.c_str() + SpacePos + 1;
|
||||
const char *End = Line.c_str() + Line.size();
|
||||
assert(Beg < End);
|
||||
size_t Len = End - Beg;
|
||||
for (size_t I = 0; I < Len; I++) {
|
||||
|
||||
if (Beg[I] != '0' && Beg[I] != '1')
|
||||
return ParseError("the trace should contain only 0 or 1", Line);
|
||||
|
||||
}
|
||||
|
||||
*DFTString = Beg;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
|
||||
Vector<SizedFile> &CorporaFiles, Random &Rand) {
|
||||
|
||||
if (DirPath.empty()) return false;
|
||||
Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());
|
||||
Vector<SizedFile> Files;
|
||||
GetSizedFilesFromDir(DirPath, &Files);
|
||||
std::string L;
|
||||
size_t FocusFuncIdx = SIZE_MAX;
|
||||
Vector<std::string> FunctionNames;
|
||||
|
||||
// Collect the hashes of the corpus files.
|
||||
for (auto &SF : CorporaFiles)
|
||||
CorporaHashes.insert(Hash(FileToVector(SF.File)));
|
||||
|
||||
// Read functions.txt
|
||||
std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt));
|
||||
size_t NumFunctions = 0;
|
||||
while (std::getline(IF, L, '\n')) {
|
||||
|
||||
FunctionNames.push_back(L);
|
||||
NumFunctions++;
|
||||
if (*FocusFunction == L) FocusFuncIdx = NumFunctions - 1;
|
||||
|
||||
}
|
||||
|
||||
if (!NumFunctions) return false;
|
||||
|
||||
if (*FocusFunction == "auto") {
|
||||
|
||||
// AUTOFOCUS works like this:
|
||||
// * reads the coverage data from the DFT files.
|
||||
// * assigns weights to functions based on coverage.
|
||||
// * chooses a random function according to the weights.
|
||||
ReadCoverage(DirPath);
|
||||
auto Weights = Coverage.FunctionWeights(NumFunctions);
|
||||
Vector<double> Intervals(NumFunctions + 1);
|
||||
std::iota(Intervals.begin(), Intervals.end(), 0);
|
||||
auto Distribution = std::piecewise_constant_distribution<double>(
|
||||
Intervals.begin(), Intervals.end(), Weights.begin());
|
||||
FocusFuncIdx = static_cast<size_t>(Distribution(Rand));
|
||||
*FocusFunction = FunctionNames[FocusFuncIdx];
|
||||
assert(FocusFuncIdx < NumFunctions);
|
||||
Printf("INFO: AUTOFOCUS: %zd %s\n", FocusFuncIdx,
|
||||
FunctionNames[FocusFuncIdx].c_str());
|
||||
for (size_t i = 0; i < NumFunctions; i++) {
|
||||
|
||||
if (!Weights[i]) continue;
|
||||
Printf(" [%zd] W %g\tBB-tot %u\tBB-cov %u\tEntryFreq %u:\t%s\n", i,
|
||||
Weights[i], Coverage.GetNumberOfBlocks(i),
|
||||
Coverage.GetNumberOfCoveredBlocks(i), Coverage.GetCounter(i, 0),
|
||||
FunctionNames[i].c_str());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
|
||||
return false;
|
||||
|
||||
// Read traces.
|
||||
size_t NumTraceFiles = 0;
|
||||
size_t NumTracesWithFocusFunction = 0;
|
||||
for (auto &SF : Files) {
|
||||
|
||||
auto Name = Basename(SF.File);
|
||||
if (Name == kFunctionsTxt) continue;
|
||||
if (!CorporaHashes.count(Name)) continue; // not in the corpus.
|
||||
NumTraceFiles++;
|
||||
// Printf("=== %s\n", Name.c_str());
|
||||
std::ifstream IF2(SF.File);
|
||||
while (std::getline(IF2, L, '\n')) {
|
||||
|
||||
size_t FunctionNum = 0;
|
||||
std::string DFTString;
|
||||
if (ParseDFTLine(L, &FunctionNum, &DFTString) &&
|
||||
FunctionNum == FocusFuncIdx) {
|
||||
|
||||
NumTracesWithFocusFunction++;
|
||||
|
||||
if (FunctionNum >= NumFunctions)
|
||||
return ParseError("N is greater than the number of functions", L);
|
||||
Traces[Name] = DFTStringToVector(DFTString);
|
||||
// Print just a few small traces.
|
||||
if (NumTracesWithFocusFunction <= 3 && DFTString.size() <= 16)
|
||||
Printf("%s => |%s|\n", Name.c_str(), std::string(DFTString).c_str());
|
||||
break; // No need to parse the following lines.
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Printf(
|
||||
"INFO: DataFlowTrace: %zd trace files, %zd functions, "
|
||||
"%zd traces with focus function\n",
|
||||
NumTraceFiles, NumFunctions, NumTracesWithFocusFunction);
|
||||
return NumTraceFiles > 0;
|
||||
|
||||
}
|
||||
|
||||
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
|
||||
const Vector<SizedFile> &CorporaFiles) {
|
||||
|
||||
Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n",
|
||||
DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size());
|
||||
if (CorporaFiles.empty()) {
|
||||
|
||||
Printf("ERROR: can't collect data flow without corpus provided.");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static char DFSanEnv[] = "DFSAN_OPTIONS=warn_unimplemented=0";
|
||||
putenv(DFSanEnv);
|
||||
MkDir(DirPath);
|
||||
for (auto &F : CorporaFiles) {
|
||||
|
||||
// For every input F we need to collect the data flow and the coverage.
|
||||
// Data flow collection may fail if we request too many DFSan tags at once.
|
||||
// So, we start from requesting all tags in range [0,Size) and if that fails
|
||||
// we then request tags in [0,Size/2) and [Size/2, Size), and so on.
|
||||
// Function number => DFT.
|
||||
auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
|
||||
// std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
|
||||
// std::unordered_set<std::string> Cov;
|
||||
Command Cmd;
|
||||
Cmd.addArgument(DFTBinary);
|
||||
Cmd.addArgument(F.File);
|
||||
Cmd.addArgument(OutPath);
|
||||
Printf("CMD: %s\n", Cmd.toString().c_str());
|
||||
ExecuteCommand(Cmd);
|
||||
|
||||
}
|
||||
|
||||
// Write functions.txt if it's currently empty or doesn't exist.
|
||||
auto FunctionsTxtPath = DirPlusFile(DirPath, kFunctionsTxt);
|
||||
if (FileToString(FunctionsTxtPath).empty()) {
|
||||
|
||||
Command Cmd;
|
||||
Cmd.addArgument(DFTBinary);
|
||||
Cmd.setOutputFile(FunctionsTxtPath);
|
||||
ExecuteCommand(Cmd);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
135
custom_mutators/libfuzzer/FuzzerDataFlowTrace.h
Normal file
135
custom_mutators/libfuzzer/FuzzerDataFlowTrace.h
Normal file
@ -0,0 +1,135 @@
|
||||
//===- FuzzerDataFlowTrace.h - Internal header for the Fuzzer ---*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::DataFlowTrace; reads and handles a data-flow trace.
|
||||
//
|
||||
// A data flow trace is generated by e.g. dataflow/DataFlow.cpp
|
||||
// and is stored on disk in a separate directory.
|
||||
//
|
||||
// The trace dir contains a file 'functions.txt' which lists function names,
|
||||
// oner per line, e.g.
|
||||
// ==> functions.txt <==
|
||||
// Func2
|
||||
// LLVMFuzzerTestOneInput
|
||||
// Func1
|
||||
//
|
||||
// All other files in the dir are the traces, see dataflow/DataFlow.cpp.
|
||||
// The name of the file is sha1 of the input used to generate the trace.
|
||||
//
|
||||
// Current status:
|
||||
// the data is parsed and the summary is printed, but the data is not yet
|
||||
// used in any other way.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_DATA_FLOW_TRACE
|
||||
#define LLVM_FUZZER_DATA_FLOW_TRACE
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
|
||||
const Vector<SizedFile> &CorporaFiles);
|
||||
|
||||
class BlockCoverage {
|
||||
public:
|
||||
bool AppendCoverage(std::istream &IN);
|
||||
bool AppendCoverage(const std::string &S);
|
||||
|
||||
size_t NumCoveredFunctions() const { return Functions.size(); }
|
||||
|
||||
uint32_t GetCounter(size_t FunctionId, size_t BasicBlockId) {
|
||||
auto It = Functions.find(FunctionId);
|
||||
if (It == Functions.end()) return 0;
|
||||
const auto &Counters = It->second;
|
||||
if (BasicBlockId < Counters.size())
|
||||
return Counters[BasicBlockId];
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetNumberOfBlocks(size_t FunctionId) {
|
||||
auto It = Functions.find(FunctionId);
|
||||
if (It == Functions.end()) return 0;
|
||||
const auto &Counters = It->second;
|
||||
return Counters.size();
|
||||
}
|
||||
|
||||
uint32_t GetNumberOfCoveredBlocks(size_t FunctionId) {
|
||||
auto It = Functions.find(FunctionId);
|
||||
if (It == Functions.end()) return 0;
|
||||
const auto &Counters = It->second;
|
||||
uint32_t Result = 0;
|
||||
for (auto Cnt: Counters)
|
||||
if (Cnt)
|
||||
Result++;
|
||||
return Result;
|
||||
}
|
||||
|
||||
Vector<double> FunctionWeights(size_t NumFunctions) const;
|
||||
void clear() { Functions.clear(); }
|
||||
|
||||
private:
|
||||
|
||||
typedef Vector<uint32_t> CoverageVector;
|
||||
|
||||
uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const {
|
||||
uint32_t Res = 0;
|
||||
for (auto Cnt : Counters)
|
||||
if (Cnt)
|
||||
Res++;
|
||||
return Res;
|
||||
}
|
||||
|
||||
uint32_t NumberOfUncoveredBlocks(const CoverageVector &Counters) const {
|
||||
return Counters.size() - NumberOfCoveredBlocks(Counters);
|
||||
}
|
||||
|
||||
uint32_t SmallestNonZeroCounter(const CoverageVector &Counters) const {
|
||||
assert(!Counters.empty());
|
||||
uint32_t Res = Counters[0];
|
||||
for (auto Cnt : Counters)
|
||||
if (Cnt)
|
||||
Res = Min(Res, Cnt);
|
||||
assert(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Function ID => vector of counters.
|
||||
// Each counter represents how many input files trigger the given basic block.
|
||||
std::unordered_map<size_t, CoverageVector> Functions;
|
||||
// Functions that have DFT entry.
|
||||
std::unordered_set<size_t> FunctionsWithDFT;
|
||||
};
|
||||
|
||||
class DataFlowTrace {
|
||||
public:
|
||||
void ReadCoverage(const std::string &DirPath);
|
||||
bool Init(const std::string &DirPath, std::string *FocusFunction,
|
||||
Vector<SizedFile> &CorporaFiles, Random &Rand);
|
||||
void Clear() { Traces.clear(); }
|
||||
const Vector<uint8_t> *Get(const std::string &InputSha1) const {
|
||||
auto It = Traces.find(InputSha1);
|
||||
if (It != Traces.end())
|
||||
return &It->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Input's sha1 => DFT for the FocusFunction.
|
||||
std::unordered_map<std::string, Vector<uint8_t> > Traces;
|
||||
BlockCoverage Coverage;
|
||||
std::unordered_set<std::string> CorporaHashes;
|
||||
};
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DATA_FLOW_TRACE
|
75
custom_mutators/libfuzzer/FuzzerDefs.h
Normal file
75
custom_mutators/libfuzzer/FuzzerDefs.h
Normal file
@ -0,0 +1,75 @@
|
||||
//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_DEFS_H
|
||||
#define LLVM_FUZZER_DEFS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
template <class T> T Min(T a, T b) { return a < b ? a : b; }
|
||||
template <class T> T Max(T a, T b) { return a > b ? a : b; }
|
||||
|
||||
class Random;
|
||||
class Dictionary;
|
||||
class DictionaryEntry;
|
||||
class MutationDispatcher;
|
||||
struct FuzzingOptions;
|
||||
class InputCorpus;
|
||||
struct InputInfo;
|
||||
struct ExternalFunctions;
|
||||
|
||||
// Global interface to functions that may or may not be available.
|
||||
extern ExternalFunctions *EF;
|
||||
|
||||
// We are using a custom allocator to give a different symbol name to STL
|
||||
// containers in order to avoid ODR violations.
|
||||
template<typename T>
|
||||
class fuzzer_allocator: public std::allocator<T> {
|
||||
public:
|
||||
fuzzer_allocator() = default;
|
||||
|
||||
template<class U>
|
||||
explicit fuzzer_allocator(const fuzzer_allocator<U>&) {}
|
||||
|
||||
template<class Other>
|
||||
struct rebind { typedef fuzzer_allocator<Other> other; };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using Vector = std::vector<T, fuzzer_allocator<T>>;
|
||||
|
||||
template<typename T>
|
||||
using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
|
||||
|
||||
typedef Vector<uint8_t> Unit;
|
||||
typedef Vector<Unit> UnitVector;
|
||||
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
|
||||
|
||||
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
|
||||
|
||||
uint8_t *ExtraCountersBegin();
|
||||
uint8_t *ExtraCountersEnd();
|
||||
void ClearExtraCounters();
|
||||
|
||||
extern bool RunningUserCallback;
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DEFS_H
|
118
custom_mutators/libfuzzer/FuzzerDictionary.h
Normal file
118
custom_mutators/libfuzzer/FuzzerDictionary.h
Normal file
@ -0,0 +1,118 @@
|
||||
//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::Dictionary
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_DICTIONARY_H
|
||||
#define LLVM_FUZZER_DICTIONARY_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerUtil.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace fuzzer {
|
||||
// A simple POD sized array of bytes.
|
||||
template <size_t kMaxSizeT> class FixedWord {
|
||||
public:
|
||||
static const size_t kMaxSize = kMaxSizeT;
|
||||
FixedWord() {}
|
||||
FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); }
|
||||
|
||||
void Set(const uint8_t *B, uint8_t S) {
|
||||
assert(S <= kMaxSize);
|
||||
memcpy(Data, B, S);
|
||||
Size = S;
|
||||
}
|
||||
|
||||
bool operator==(const FixedWord<kMaxSize> &w) const {
|
||||
return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
|
||||
}
|
||||
|
||||
static size_t GetMaxSize() { return kMaxSize; }
|
||||
const uint8_t *data() const { return Data; }
|
||||
uint8_t size() const { return Size; }
|
||||
|
||||
private:
|
||||
uint8_t Size = 0;
|
||||
uint8_t Data[kMaxSize];
|
||||
};
|
||||
|
||||
typedef FixedWord<64> Word;
|
||||
|
||||
class DictionaryEntry {
|
||||
public:
|
||||
DictionaryEntry() {}
|
||||
explicit DictionaryEntry(Word W) : W(W) {}
|
||||
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
|
||||
const Word &GetW() const { return W; }
|
||||
|
||||
bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
|
||||
size_t GetPositionHint() const {
|
||||
assert(HasPositionHint());
|
||||
return PositionHint;
|
||||
}
|
||||
void IncUseCount() { UseCount++; }
|
||||
void IncSuccessCount() { SuccessCount++; }
|
||||
size_t GetUseCount() const { return UseCount; }
|
||||
size_t GetSuccessCount() const {return SuccessCount; }
|
||||
|
||||
void Print(const char *PrintAfter = "\n") {
|
||||
PrintASCII(W.data(), W.size());
|
||||
if (HasPositionHint())
|
||||
Printf("@%zd", GetPositionHint());
|
||||
Printf("%s", PrintAfter);
|
||||
}
|
||||
|
||||
private:
|
||||
Word W;
|
||||
size_t PositionHint = std::numeric_limits<size_t>::max();
|
||||
size_t UseCount = 0;
|
||||
size_t SuccessCount = 0;
|
||||
};
|
||||
|
||||
class Dictionary {
|
||||
public:
|
||||
static const size_t kMaxDictSize = 1 << 14;
|
||||
|
||||
bool ContainsWord(const Word &W) const {
|
||||
return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
|
||||
return DE.GetW() == W;
|
||||
});
|
||||
}
|
||||
const DictionaryEntry *begin() const { return &DE[0]; }
|
||||
const DictionaryEntry *end() const { return begin() + Size; }
|
||||
DictionaryEntry & operator[] (size_t Idx) {
|
||||
assert(Idx < Size);
|
||||
return DE[Idx];
|
||||
}
|
||||
void push_back(const DictionaryEntry &DE) {
|
||||
if (Size < kMaxDictSize)
|
||||
this->DE[Size++] = DE;
|
||||
}
|
||||
void clear() { Size = 0; }
|
||||
bool empty() const { return Size == 0; }
|
||||
size_t size() const { return Size; }
|
||||
|
||||
private:
|
||||
DictionaryEntry DE[kMaxDictSize];
|
||||
size_t Size = 0;
|
||||
};
|
||||
|
||||
// Parses one dictionary entry.
|
||||
// If successful, write the enty to Unit and returns true,
|
||||
// otherwise returns false.
|
||||
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
|
||||
// Parses the dictionary file, fills Units, returns true iff all lines
|
||||
// were parsed successfully.
|
||||
bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DICTIONARY_H
|
1111
custom_mutators/libfuzzer/FuzzerDriver.cpp
Normal file
1111
custom_mutators/libfuzzer/FuzzerDriver.cpp
Normal file
File diff suppressed because it is too large
Load Diff
50
custom_mutators/libfuzzer/FuzzerExtFunctions.def
Normal file
50
custom_mutators/libfuzzer/FuzzerExtFunctions.def
Normal file
@ -0,0 +1,50 @@
|
||||
//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This defines the external function pointers that
|
||||
// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The
|
||||
// EXT_FUNC macro must be defined at the point of inclusion. The signature of
|
||||
// the macro is:
|
||||
//
|
||||
// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Optional user functions
|
||||
EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
|
||||
EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
|
||||
(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed),
|
||||
false);
|
||||
EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
|
||||
(const uint8_t *Data1, size_t Size1,
|
||||
const uint8_t *Data2, size_t Size2,
|
||||
uint8_t *Out, size_t MaxOutSize, unsigned int Seed),
|
||||
false);
|
||||
|
||||
// Sanitizer functions
|
||||
EXT_FUNC(__lsan_enable, void, (), false);
|
||||
EXT_FUNC(__lsan_disable, void, (), false);
|
||||
EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
|
||||
EXT_FUNC(__sanitizer_acquire_crash_state, int, (), true);
|
||||
EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
|
||||
(void (*malloc_hook)(const volatile void *, size_t),
|
||||
void (*free_hook)(const volatile void *)),
|
||||
false);
|
||||
EXT_FUNC(__sanitizer_log_write, void, (const char *buf, size_t len), false);
|
||||
EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
|
||||
EXT_FUNC(__sanitizer_print_memory_profile, void, (size_t, size_t), false);
|
||||
EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
|
||||
EXT_FUNC(__sanitizer_symbolize_pc, void,
|
||||
(void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
|
||||
EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
|
||||
(void *pc, char *module_path,
|
||||
size_t module_path_len,void **pc_offset), false);
|
||||
EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
|
||||
EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
|
||||
EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false);
|
||||
EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false);
|
||||
EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false);
|
||||
EXT_FUNC(__msan_unpoison_param, void, (size_t n), false);
|
34
custom_mutators/libfuzzer/FuzzerExtFunctions.h
Normal file
34
custom_mutators/libfuzzer/FuzzerExtFunctions.h
Normal file
@ -0,0 +1,34 @@
|
||||
//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Defines an interface to (possibly optional) functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H
|
||||
#define LLVM_FUZZER_EXT_FUNCTIONS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct ExternalFunctions {
|
||||
// Initialize function pointers. Functions that are not available will be set
|
||||
// to nullptr. Do not call this constructor before ``main()`` has been
|
||||
// entered.
|
||||
ExternalFunctions();
|
||||
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE(*NAME) FUNC_SIG = nullptr
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
};
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif
|
60
custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp
Normal file
60
custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation for operating systems that support dlsym(). We only use it on
|
||||
// Apple platforms for now. We don't use this approach on Linux because it
|
||||
// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker.
|
||||
// That is a complication we don't wish to expose to clients right now.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerPlatform.h"
|
||||
#if LIBFUZZER_APPLE
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
template <typename T>
|
||||
static T GetFnPtr(const char *FnName, bool WarnIfMissing) {
|
||||
|
||||
dlerror(); // Clear any previous errors.
|
||||
void *Fn = dlsym(RTLD_DEFAULT, FnName);
|
||||
if (Fn == nullptr) {
|
||||
|
||||
if (WarnIfMissing) {
|
||||
|
||||
const char *ErrorMsg = dlerror();
|
||||
Printf("WARNING: Failed to find function \"%s\".", FnName);
|
||||
if (ErrorMsg) Printf(" Reason %s.", ErrorMsg);
|
||||
Printf("\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return reinterpret_cast<T>(Fn);
|
||||
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
\
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN)
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_APPLE
|
||||
|
63
custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp
Normal file
63
custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation for Linux. This relies on the linker's support for weak
|
||||
// symbols. We don't use this approach on Apple platforms because it requires
|
||||
// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
|
||||
// weak symbols to be undefined. That is a complication we don't want to expose
|
||||
// to clients right now.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerPlatform.h"
|
||||
#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA || \
|
||||
LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Declare these symbols as weak to allow them to be optionally defined.
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
|
||||
}
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
|
||||
|
||||
if (FnPtr == nullptr && WarnIfMissing) {
|
||||
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
\
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = ::NAME; \
|
||||
CheckFnPtr(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(::NAME)), \
|
||||
#NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif
|
||||
|
95
custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp
Normal file
95
custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
//=== FuzzerExtWindows.cpp - Interface to external functions --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation of FuzzerExtFunctions for Windows. Uses alternatename when
|
||||
// compiled with MSVC. Uses weak aliases when compiled with clang. Unfortunately
|
||||
// the method each compiler supports is not supported by the other.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerPlatform.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
// Intermediate macro to ensure the parameter is expanded before stringified.
|
||||
#define STRINGIFY_(A) #A
|
||||
#define STRINGIFY(A) STRINGIFY_(A)
|
||||
|
||||
#if LIBFUZZER_MSVC
|
||||
// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define WIN_SYM_PREFIX "_"
|
||||
#else
|
||||
#define WIN_SYM_PREFIX
|
||||
#endif
|
||||
|
||||
// Declare external functions as having alternativenames, so that we can
|
||||
// determine if they are not defined.
|
||||
#define EXTERNAL_FUNC(Name, Default) \
|
||||
__pragma( \
|
||||
comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
|
||||
Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
|
||||
#else
|
||||
// Declare external functions as weak to allow them to default to a
|
||||
// specified function if not defined explicitly. We must use weak symbols
|
||||
// because clang's support for alternatename is not 100%, see
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details.
|
||||
#define EXTERNAL_FUNC(Name, Default) \
|
||||
__attribute__((weak, alias(STRINGIFY(Default))))
|
||||
#endif // LIBFUZZER_MSVC
|
||||
|
||||
extern "C" {
|
||||
\
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE NAME##Def FUNC_SIG { \
|
||||
\
|
||||
Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
|
||||
exit(1); \
|
||||
\
|
||||
} \
|
||||
EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
|
||||
|
||||
if (Fun == FunDef) {
|
||||
|
||||
if (WarnIfMissing)
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
return Fun;
|
||||
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
\
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
|
71
custom_mutators/libfuzzer/FuzzerExtraCounters.cpp
Normal file
71
custom_mutators/libfuzzer/FuzzerExtraCounters.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra coverage counters defined by user code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerPlatform.h"
|
||||
#include <cstdint>
|
||||
|
||||
#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD || \
|
||||
LIBFUZZER_OPENBSD || LIBFUZZER_FUCHSIA || LIBFUZZER_EMSCRIPTEN
|
||||
__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;
|
||||
__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters;
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
uint8_t *ExtraCountersBegin() {
|
||||
|
||||
return &__start___libfuzzer_extra_counters;
|
||||
|
||||
}
|
||||
|
||||
uint8_t *ExtraCountersEnd() {
|
||||
|
||||
return &__stop___libfuzzer_extra_counters;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void ClearExtraCounters() { // hand-written memset, don't asan-ify.
|
||||
uintptr_t *Beg = reinterpret_cast<uintptr_t *>(ExtraCountersBegin());
|
||||
uintptr_t *End = reinterpret_cast<uintptr_t *>(ExtraCountersEnd());
|
||||
for (; Beg < End; Beg++) {
|
||||
|
||||
*Beg = 0;
|
||||
__asm__ __volatile__("" : : : "memory");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#else
|
||||
// TODO: implement for other platforms.
|
||||
namespace fuzzer {
|
||||
|
||||
uint8_t *ExtraCountersBegin() {
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
uint8_t *ExtraCountersEnd() {
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void ClearExtraCounters() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif
|
||||
|
198
custom_mutators/libfuzzer/FuzzerFlags.def
Normal file
198
custom_mutators/libfuzzer/FuzzerFlags.def
Normal file
@ -0,0 +1,198 @@
|
||||
//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the
|
||||
// point of inclusion. We are not using any flag parsing library for better
|
||||
// portability and independence.
|
||||
//===----------------------------------------------------------------------===//
|
||||
FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
|
||||
FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
|
||||
FUZZER_FLAG_INT(runs, -1,
|
||||
"Number of individual test runs (-1 for infinite runs).")
|
||||
FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
|
||||
"If 0, libFuzzer tries to guess a good value based on the corpus "
|
||||
"and reports it. ")
|
||||
FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, "
|
||||
"then try larger inputs over time. Specifies the rate at which the length "
|
||||
"limit is increased (smaller == faster). If 0, immediately try inputs with "
|
||||
"size up to max_len. Default value is 0, if LLVMFuzzerCustomMutator is used.")
|
||||
FUZZER_FLAG_STRING(seed_inputs, "A comma-separated list of input files "
|
||||
"to use as an additional seed corpus. Alternatively, an \"@\" followed by "
|
||||
"the name of a file containing the comma-separated list.")
|
||||
FUZZER_FLAG_INT(keep_seed, 0, "If 1, keep seed inputs in the corpus even if "
|
||||
"they do not produce new coverage. When used with |reduce_inputs==1|, the "
|
||||
"seed inputs will never be reduced. This option can be useful when seeds are"
|
||||
"not properly formed for the fuzz target but still have useful snippets.")
|
||||
FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.")
|
||||
FUZZER_FLAG_INT(cross_over_uniform_dist, 0, "Experimental. If 1, use a "
|
||||
"uniform probability distribution when choosing inputs to cross over with. "
|
||||
"Some of the inputs in the corpus may never get chosen for mutation "
|
||||
"depending on the input mutation scheduling policy. With this flag, all "
|
||||
"inputs, regardless of the input mutation scheduling policy, can be chosen "
|
||||
"as an input to cross over with. This can be particularly useful with "
|
||||
"|keep_seed==1|; all the initial seed inputs, even though they do not "
|
||||
"increase coverage because they are not properly formed, will still be "
|
||||
"chosen as an input to cross over with.")
|
||||
|
||||
FUZZER_FLAG_INT(mutate_depth, 5,
|
||||
"Apply this number of consecutive mutations to each input.")
|
||||
FUZZER_FLAG_INT(reduce_depth, 0, "Experimental/internal. "
|
||||
"Reduce depth if mutations lose unique features")
|
||||
FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup")
|
||||
FUZZER_FLAG_INT(prefer_small, 1,
|
||||
"If 1, always prefer smaller inputs during the corpus shuffle.")
|
||||
FUZZER_FLAG_INT(
|
||||
timeout, 1200,
|
||||
"Timeout in seconds (if positive). "
|
||||
"If one unit runs more than this number of seconds the process will abort.")
|
||||
FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
|
||||
"this exit code will be used.")
|
||||
FUZZER_FLAG_INT(timeout_exitcode, 70, "When libFuzzer reports a timeout "
|
||||
"this exit code will be used.")
|
||||
FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
|
||||
"time in seconds to run the fuzzer.")
|
||||
FUZZER_FLAG_INT(help, 0, "Print help.")
|
||||
FUZZER_FLAG_INT(fork, 0, "Experimental mode where fuzzing happens "
|
||||
"in a subprocess")
|
||||
FUZZER_FLAG_INT(ignore_timeouts, 1, "Ignore timeouts in fork mode")
|
||||
FUZZER_FLAG_INT(ignore_ooms, 1, "Ignore OOMs in fork mode")
|
||||
FUZZER_FLAG_INT(ignore_crashes, 0, "Ignore crashes in fork mode")
|
||||
FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
|
||||
"merged into the 1-st corpus. Only interesting units will be taken. "
|
||||
"This flag can be used to minimize a corpus.")
|
||||
FUZZER_FLAG_STRING(stop_file, "Stop fuzzing ASAP if this file exists")
|
||||
FUZZER_FLAG_STRING(merge_inner, "internal flag")
|
||||
FUZZER_FLAG_STRING(merge_control_file,
|
||||
"Specify a control file used for the merge process. "
|
||||
"If a merge process gets killed it tries to leave this file "
|
||||
"in a state suitable for resuming the merge. "
|
||||
"By default a temporary file will be used."
|
||||
"The same file can be used for multistep merge process.")
|
||||
FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
|
||||
" crash input. Use with -runs=N or -max_total_time=N to limit "
|
||||
"the number attempts."
|
||||
" Use with -exact_artifact_path to specify the output."
|
||||
" Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that"
|
||||
" the minimized input triggers the same crash."
|
||||
)
|
||||
FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided"
|
||||
" crash input to make it contain fewer original bytes."
|
||||
" Use with -exact_artifact_path to specify the output."
|
||||
)
|
||||
FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag")
|
||||
FUZZER_FLAG_STRING(features_dir, "internal flag. Used to dump feature sets on disk."
|
||||
"Every time a new input is added to the corpus, a corresponding file in the features_dir"
|
||||
" is created containing the unique features of that input."
|
||||
" Features are stored in binary format.")
|
||||
FUZZER_FLAG_STRING(mutation_graph_file, "Saves a graph (in DOT format) to"
|
||||
" mutation_graph_file. The graph contains a vertex for each input that has"
|
||||
" unique coverage; directed edges are provided between parents and children"
|
||||
" where the child has unique coverage, and are recorded with the type of"
|
||||
" mutation that caused the child.")
|
||||
FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
|
||||
FUZZER_FLAG_INT(use_memmem, 1,
|
||||
"Use hints from intercepting memmem, strstr, etc")
|
||||
FUZZER_FLAG_INT(use_value_profile, 0,
|
||||
"Experimental. Use value profile to guide fuzzing.")
|
||||
FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations")
|
||||
FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.")
|
||||
FUZZER_FLAG_INT(reduce_inputs, 1,
|
||||
"Try to reduce the size of inputs while preserving their full feature sets")
|
||||
FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
|
||||
" this number of jobs in separate worker processes"
|
||||
" with stdout/stderr redirected to fuzz-JOB.log.")
|
||||
FUZZER_FLAG_UNSIGNED(workers, 0,
|
||||
"Number of simultaneous worker processes to run the jobs."
|
||||
" If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
|
||||
FUZZER_FLAG_INT(reload, 1,
|
||||
"Reload the main corpus every <N> seconds to get new units"
|
||||
" discovered by other processes. If 0, disabled")
|
||||
FUZZER_FLAG_INT(report_slow_units, 10,
|
||||
"Report slowest units if they run for more than this number of seconds.")
|
||||
FUZZER_FLAG_INT(only_ascii, 0,
|
||||
"If 1, generate only ASCII (isprint+isspace) inputs.")
|
||||
FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
|
||||
FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
|
||||
"timeout, or slow inputs) as "
|
||||
"$(artifact_prefix)file")
|
||||
FUZZER_FLAG_STRING(exact_artifact_path,
|
||||
"Write the single artifact on failure (crash, timeout) "
|
||||
"as $(exact_artifact_path). This overrides -artifact_prefix "
|
||||
"and will not use checksum in the file name. Do not "
|
||||
"use the same path for several parallel processes.")
|
||||
FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
|
||||
FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of "
|
||||
"newly covered functions.")
|
||||
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
|
||||
FUZZER_FLAG_INT(print_corpus_stats, 0,
|
||||
"If 1, print statistics on corpus elements at exit.")
|
||||
FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
|
||||
" at exit.")
|
||||
FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated.")
|
||||
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
|
||||
FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
|
||||
FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
|
||||
FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
|
||||
FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
|
||||
FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
|
||||
FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
|
||||
FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
|
||||
FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
|
||||
FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
|
||||
FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
|
||||
"if 2, close stderr; if 3, close both. "
|
||||
"Be careful, this will also close e.g. stderr of asan.")
|
||||
FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
|
||||
"try to detect memory leaks during fuzzing (i.e. not only at shut down).")
|
||||
FUZZER_FLAG_INT(purge_allocator_interval, 1, "Purge allocator caches and "
|
||||
"quarantines every <N> seconds. When rss_limit_mb is specified (>0), "
|
||||
"purging starts when RSS exceeds 50% of rss_limit_mb. Pass "
|
||||
"purge_allocator_interval=-1 to disable this functionality.")
|
||||
FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
|
||||
"If >= 2 will also print stack traces.")
|
||||
FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
|
||||
"reaching this limit of RSS memory usage.")
|
||||
FUZZER_FLAG_INT(malloc_limit_mb, 0, "If non-zero, the fuzzer will exit "
|
||||
"if the target tries to allocate this number of Mb with one malloc call. "
|
||||
"If zero (default) same limit as rss_limit_mb is applied.")
|
||||
FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
|
||||
" from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
|
||||
"Used primarily for testing libFuzzer itself.")
|
||||
FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
|
||||
" was added to the corpus. "
|
||||
"Used primarily for testing libFuzzer itself.")
|
||||
FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed "
|
||||
"after this one. Useful for fuzzers that need to do their own "
|
||||
"argument parsing.")
|
||||
FUZZER_FLAG_STRING(focus_function, "Experimental. "
|
||||
"Fuzzing will focus on inputs that trigger calls to this function. "
|
||||
"If -focus_function=auto and -data_flow_trace is used, libFuzzer "
|
||||
"will choose the focus functions automatically. Disables -entropic when "
|
||||
"specified.")
|
||||
FUZZER_FLAG_INT(entropic, 1, "Enables entropic power schedule.")
|
||||
FUZZER_FLAG_INT(entropic_feature_frequency_threshold, 0xFF, "Experimental. If "
|
||||
"entropic is enabled, all features which are observed less often than "
|
||||
"the specified value are considered as rare.")
|
||||
FUZZER_FLAG_INT(entropic_number_of_rarest_features, 100, "Experimental. If "
|
||||
"entropic is enabled, we keep track of the frequencies only for the "
|
||||
"Top-X least abundant features (union features that are considered as "
|
||||
"rare).")
|
||||
FUZZER_FLAG_INT(entropic_scale_per_exec_time, 0, "Experimental. If 1, "
|
||||
"the Entropic power schedule gets scaled based on the input execution "
|
||||
"time. Inputs with lower execution time get scheduled more (up to 30x). "
|
||||
"Note that, if 1, fuzzer stops from being deterministic even if a "
|
||||
"non-zero random seed is given.")
|
||||
|
||||
FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
|
||||
FUZZER_DEPRECATED_FLAG(use_clang_coverage)
|
||||
FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace")
|
||||
FUZZER_FLAG_STRING(collect_data_flow,
|
||||
"Experimental: collect the data flow trace")
|
||||
|
||||
FUZZER_FLAG_INT(create_missing_dirs, 0, "Automatically attempt to create "
|
||||
"directories for arguments that would normally expect them to already "
|
||||
"exist (i.e. artifact_prefix, exact_artifact_path, features_dir, corpus)")
|
501
custom_mutators/libfuzzer/FuzzerFork.cpp
Normal file
501
custom_mutators/libfuzzer/FuzzerFork.cpp
Normal file
@ -0,0 +1,501 @@
|
||||
//===- FuzzerFork.cpp - run fuzzing in separate subprocesses --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Spawn and orchestrate separate fuzzing processes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCommand.h"
|
||||
#include "FuzzerFork.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerMerge.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "FuzzerUtil.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct Stats {
|
||||
|
||||
size_t number_of_executed_units = 0;
|
||||
size_t peak_rss_mb = 0;
|
||||
size_t average_exec_per_sec = 0;
|
||||
|
||||
};
|
||||
|
||||
static Stats ParseFinalStatsFromLog(const std::string &LogPath) {
|
||||
|
||||
std::ifstream In(LogPath);
|
||||
std::string Line;
|
||||
Stats Res;
|
||||
struct {
|
||||
|
||||
const char *Name;
|
||||
size_t * Var;
|
||||
|
||||
} NameVarPairs[] = {
|
||||
|
||||
{"stat::number_of_executed_units:", &Res.number_of_executed_units},
|
||||
{"stat::peak_rss_mb:", &Res.peak_rss_mb},
|
||||
{"stat::average_exec_per_sec:", &Res.average_exec_per_sec},
|
||||
{nullptr, nullptr},
|
||||
|
||||
};
|
||||
|
||||
while (std::getline(In, Line, '\n')) {
|
||||
|
||||
if (Line.find("stat::") != 0) continue;
|
||||
std::istringstream ISS(Line);
|
||||
std::string Name;
|
||||
size_t Val;
|
||||
ISS >> Name >> Val;
|
||||
for (size_t i = 0; NameVarPairs[i].Name; i++)
|
||||
if (Name == NameVarPairs[i].Name) *NameVarPairs[i].Var = Val;
|
||||
|
||||
}
|
||||
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
struct FuzzJob {
|
||||
|
||||
// Inputs.
|
||||
Command Cmd;
|
||||
std::string CorpusDir;
|
||||
std::string FeaturesDir;
|
||||
std::string LogPath;
|
||||
std::string SeedListPath;
|
||||
std::string CFPath;
|
||||
size_t JobId;
|
||||
|
||||
int DftTimeInSeconds = 0;
|
||||
|
||||
// Fuzzing Outputs.
|
||||
int ExitCode;
|
||||
|
||||
~FuzzJob() {
|
||||
|
||||
RemoveFile(CFPath);
|
||||
RemoveFile(LogPath);
|
||||
RemoveFile(SeedListPath);
|
||||
RmDirRecursive(CorpusDir);
|
||||
RmDirRecursive(FeaturesDir);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct GlobalEnv {
|
||||
|
||||
Vector<std::string> Args;
|
||||
Vector<std::string> CorpusDirs;
|
||||
std::string MainCorpusDir;
|
||||
std::string TempDir;
|
||||
std::string DFTDir;
|
||||
std::string DataFlowBinary;
|
||||
Set<uint32_t> Features, Cov;
|
||||
Set<std::string> FilesWithDFT;
|
||||
Vector<std::string> Files;
|
||||
Random * Rand;
|
||||
std::chrono::system_clock::time_point ProcessStartTime;
|
||||
int Verbosity = 0;
|
||||
|
||||
size_t NumTimeouts = 0;
|
||||
size_t NumOOMs = 0;
|
||||
size_t NumCrashes = 0;
|
||||
|
||||
size_t NumRuns = 0;
|
||||
|
||||
std::string StopFile() {
|
||||
|
||||
return DirPlusFile(TempDir, "STOP");
|
||||
|
||||
}
|
||||
|
||||
size_t secondsSinceProcessStartUp() const {
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now() - ProcessStartTime)
|
||||
.count();
|
||||
|
||||
}
|
||||
|
||||
FuzzJob *CreateNewJob(size_t JobId) {
|
||||
|
||||
Command Cmd(Args);
|
||||
Cmd.removeFlag("fork");
|
||||
Cmd.removeFlag("runs");
|
||||
Cmd.removeFlag("collect_data_flow");
|
||||
for (auto &C : CorpusDirs) // Remove all corpora from the args.
|
||||
Cmd.removeArgument(C);
|
||||
Cmd.addFlag("reload", "0"); // working in an isolated dir, no reload.
|
||||
Cmd.addFlag("print_final_stats", "1");
|
||||
Cmd.addFlag("print_funcs", "0"); // no need to spend time symbolizing.
|
||||
Cmd.addFlag("max_total_time", std::to_string(std::min((size_t)300, JobId)));
|
||||
Cmd.addFlag("stop_file", StopFile());
|
||||
if (!DataFlowBinary.empty()) {
|
||||
|
||||
Cmd.addFlag("data_flow_trace", DFTDir);
|
||||
if (!Cmd.hasFlag("focus_function")) Cmd.addFlag("focus_function", "auto");
|
||||
|
||||
}
|
||||
|
||||
auto Job = new FuzzJob;
|
||||
std::string Seeds;
|
||||
if (size_t CorpusSubsetSize =
|
||||
std::min(Files.size(), (size_t)sqrt(Files.size() + 2))) {
|
||||
|
||||
auto Time1 = std::chrono::system_clock::now();
|
||||
for (size_t i = 0; i < CorpusSubsetSize; i++) {
|
||||
|
||||
auto &SF = Files[Rand->SkewTowardsLast(Files.size())];
|
||||
Seeds += (Seeds.empty() ? "" : ",") + SF;
|
||||
CollectDFT(SF);
|
||||
|
||||
}
|
||||
|
||||
auto Time2 = std::chrono::system_clock::now();
|
||||
Job->DftTimeInSeconds = duration_cast<seconds>(Time2 - Time1).count();
|
||||
|
||||
}
|
||||
|
||||
if (!Seeds.empty()) {
|
||||
|
||||
Job->SeedListPath =
|
||||
DirPlusFile(TempDir, std::to_string(JobId) + ".seeds");
|
||||
WriteToFile(Seeds, Job->SeedListPath);
|
||||
Cmd.addFlag("seed_inputs", "@" + Job->SeedListPath);
|
||||
|
||||
}
|
||||
|
||||
Job->LogPath = DirPlusFile(TempDir, std::to_string(JobId) + ".log");
|
||||
Job->CorpusDir = DirPlusFile(TempDir, "C" + std::to_string(JobId));
|
||||
Job->FeaturesDir = DirPlusFile(TempDir, "F" + std::to_string(JobId));
|
||||
Job->CFPath = DirPlusFile(TempDir, std::to_string(JobId) + ".merge");
|
||||
Job->JobId = JobId;
|
||||
|
||||
Cmd.addArgument(Job->CorpusDir);
|
||||
Cmd.addFlag("features_dir", Job->FeaturesDir);
|
||||
|
||||
for (auto &D : {Job->CorpusDir, Job->FeaturesDir}) {
|
||||
|
||||
RmDirRecursive(D);
|
||||
MkDir(D);
|
||||
|
||||
}
|
||||
|
||||
Cmd.setOutputFile(Job->LogPath);
|
||||
Cmd.combineOutAndErr();
|
||||
|
||||
Job->Cmd = Cmd;
|
||||
|
||||
if (Verbosity >= 2)
|
||||
Printf("Job %zd/%p Created: %s\n", JobId, Job,
|
||||
Job->Cmd.toString().c_str());
|
||||
// Start from very short runs and gradually increase them.
|
||||
return Job;
|
||||
|
||||
}
|
||||
|
||||
void RunOneMergeJob(FuzzJob *Job) {
|
||||
|
||||
auto Stats = ParseFinalStatsFromLog(Job->LogPath);
|
||||
NumRuns += Stats.number_of_executed_units;
|
||||
|
||||
Vector<SizedFile> TempFiles, MergeCandidates;
|
||||
// Read all newly created inputs and their feature sets.
|
||||
// Choose only those inputs that have new features.
|
||||
GetSizedFilesFromDir(Job->CorpusDir, &TempFiles);
|
||||
std::sort(TempFiles.begin(), TempFiles.end());
|
||||
for (auto &F : TempFiles) {
|
||||
|
||||
auto FeatureFile = F.File;
|
||||
FeatureFile.replace(0, Job->CorpusDir.size(), Job->FeaturesDir);
|
||||
auto FeatureBytes = FileToVector(FeatureFile, 0, false);
|
||||
assert((FeatureBytes.size() % sizeof(uint32_t)) == 0);
|
||||
Vector<uint32_t> NewFeatures(FeatureBytes.size() / sizeof(uint32_t));
|
||||
memcpy(NewFeatures.data(), FeatureBytes.data(), FeatureBytes.size());
|
||||
for (auto Ft : NewFeatures) {
|
||||
|
||||
if (!Features.count(Ft)) {
|
||||
|
||||
MergeCandidates.push_back(F);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if (!FilesToAdd.empty() || Job->ExitCode != 0)
|
||||
Printf(
|
||||
"#%zd: cov: %zd ft: %zd corp: %zd exec/s %zd "
|
||||
"oom/timeout/crash: %zd/%zd/%zd time: %zds job: %zd dft_time: %d\n",
|
||||
NumRuns, Cov.size(), Features.size(), Files.size(),
|
||||
Stats.average_exec_per_sec, NumOOMs, NumTimeouts, NumCrashes,
|
||||
secondsSinceProcessStartUp(), Job->JobId, Job->DftTimeInSeconds);
|
||||
|
||||
if (MergeCandidates.empty()) return;
|
||||
|
||||
Vector<std::string> FilesToAdd;
|
||||
Set<uint32_t> NewFeatures, NewCov;
|
||||
CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features,
|
||||
&NewFeatures, Cov, &NewCov, Job->CFPath, false);
|
||||
for (auto &Path : FilesToAdd) {
|
||||
|
||||
auto U = FileToVector(Path);
|
||||
auto NewPath = DirPlusFile(MainCorpusDir, Hash(U));
|
||||
WriteToFile(U, NewPath);
|
||||
Files.push_back(NewPath);
|
||||
|
||||
}
|
||||
|
||||
Features.insert(NewFeatures.begin(), NewFeatures.end());
|
||||
Cov.insert(NewCov.begin(), NewCov.end());
|
||||
for (auto Idx : NewCov)
|
||||
if (auto *TE = TPC.PCTableEntryByIdx(Idx))
|
||||
if (TPC.PcIsFuncEntry(TE))
|
||||
PrintPC(" NEW_FUNC: %p %F %L\n", "",
|
||||
TPC.GetNextInstructionPc(TE->PC));
|
||||
|
||||
}
|
||||
|
||||
void CollectDFT(const std::string &InputPath) {
|
||||
|
||||
if (DataFlowBinary.empty()) return;
|
||||
if (!FilesWithDFT.insert(InputPath).second) return;
|
||||
Command Cmd(Args);
|
||||
Cmd.removeFlag("fork");
|
||||
Cmd.removeFlag("runs");
|
||||
Cmd.addFlag("data_flow_trace", DFTDir);
|
||||
Cmd.addArgument(InputPath);
|
||||
for (auto &C : CorpusDirs) // Remove all corpora from the args.
|
||||
Cmd.removeArgument(C);
|
||||
Cmd.setOutputFile(DirPlusFile(TempDir, "dft.log"));
|
||||
Cmd.combineOutAndErr();
|
||||
// Printf("CollectDFT: %s\n", Cmd.toString().c_str());
|
||||
ExecuteCommand(Cmd);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct JobQueue {
|
||||
|
||||
std::queue<FuzzJob *> Qu;
|
||||
std::mutex Mu;
|
||||
std::condition_variable Cv;
|
||||
|
||||
void Push(FuzzJob *Job) {
|
||||
|
||||
{
|
||||
|
||||
std::lock_guard<std::mutex> Lock(Mu);
|
||||
Qu.push(Job);
|
||||
|
||||
}
|
||||
|
||||
Cv.notify_one();
|
||||
|
||||
}
|
||||
|
||||
FuzzJob *Pop() {
|
||||
|
||||
std::unique_lock<std::mutex> Lk(Mu);
|
||||
// std::lock_guard<std::mutex> Lock(Mu);
|
||||
Cv.wait(Lk, [&] { return !Qu.empty(); });
|
||||
assert(!Qu.empty());
|
||||
auto Job = Qu.front();
|
||||
Qu.pop();
|
||||
return Job;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) {
|
||||
|
||||
while (auto Job = FuzzQ->Pop()) {
|
||||
|
||||
// Printf("WorkerThread: job %p\n", Job);
|
||||
Job->ExitCode = ExecuteCommand(Job->Cmd);
|
||||
MergeQ->Push(Job);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This is just a skeleton of an experimental -fork=1 feature.
|
||||
void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
|
||||
const Vector<std::string> &Args,
|
||||
const Vector<std::string> &CorpusDirs, int NumJobs) {
|
||||
|
||||
Printf("INFO: -fork=%d: fuzzing in separate process(s)\n", NumJobs);
|
||||
|
||||
GlobalEnv Env;
|
||||
Env.Args = Args;
|
||||
Env.CorpusDirs = CorpusDirs;
|
||||
Env.Rand = &Rand;
|
||||
Env.Verbosity = Options.Verbosity;
|
||||
Env.ProcessStartTime = std::chrono::system_clock::now();
|
||||
Env.DataFlowBinary = Options.CollectDataFlow;
|
||||
|
||||
Vector<SizedFile> SeedFiles;
|
||||
for (auto &Dir : CorpusDirs)
|
||||
GetSizedFilesFromDir(Dir, &SeedFiles);
|
||||
std::sort(SeedFiles.begin(), SeedFiles.end());
|
||||
Env.TempDir = TempPath("FuzzWithFork", ".dir");
|
||||
Env.DFTDir = DirPlusFile(Env.TempDir, "DFT");
|
||||
RmDirRecursive(Env.TempDir); // in case there is a leftover from old runs.
|
||||
MkDir(Env.TempDir);
|
||||
MkDir(Env.DFTDir);
|
||||
|
||||
if (CorpusDirs.empty())
|
||||
MkDir(Env.MainCorpusDir = DirPlusFile(Env.TempDir, "C"));
|
||||
else
|
||||
Env.MainCorpusDir = CorpusDirs[0];
|
||||
|
||||
if (Options.KeepSeed) {
|
||||
|
||||
for (auto &File : SeedFiles)
|
||||
Env.Files.push_back(File.File);
|
||||
|
||||
} else {
|
||||
|
||||
auto CFPath = DirPlusFile(Env.TempDir, "merge.txt");
|
||||
CrashResistantMerge(Env.Args, {}, SeedFiles, &Env.Files, {}, &Env.Features,
|
||||
{}, &Env.Cov, CFPath, false);
|
||||
RemoveFile(CFPath);
|
||||
|
||||
}
|
||||
|
||||
Printf("INFO: -fork=%d: %zd seed inputs, starting to fuzz in %s\n", NumJobs,
|
||||
Env.Files.size(), Env.TempDir.c_str());
|
||||
|
||||
int ExitCode = 0;
|
||||
|
||||
JobQueue FuzzQ, MergeQ;
|
||||
|
||||
auto StopJobs = [&]() {
|
||||
|
||||
for (int i = 0; i < NumJobs; i++)
|
||||
FuzzQ.Push(nullptr);
|
||||
MergeQ.Push(nullptr);
|
||||
WriteToFile(Unit({1}), Env.StopFile());
|
||||
|
||||
};
|
||||
|
||||
size_t JobId = 1;
|
||||
Vector<std::thread> Threads;
|
||||
for (int t = 0; t < NumJobs; t++) {
|
||||
|
||||
Threads.push_back(std::thread(WorkerThread, &FuzzQ, &MergeQ));
|
||||
FuzzQ.Push(Env.CreateNewJob(JobId++));
|
||||
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
std::unique_ptr<FuzzJob> Job(MergeQ.Pop());
|
||||
if (!Job) break;
|
||||
ExitCode = Job->ExitCode;
|
||||
if (ExitCode == Options.InterruptExitCode) {
|
||||
|
||||
Printf("==%lu== libFuzzer: a child was interrupted; exiting\n", GetPid());
|
||||
StopJobs();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Fuzzer::MaybeExitGracefully();
|
||||
|
||||
Env.RunOneMergeJob(Job.get());
|
||||
|
||||
// Continue if our crash is one of the ignorred ones.
|
||||
if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
|
||||
Env.NumTimeouts++;
|
||||
else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode)
|
||||
Env.NumOOMs++;
|
||||
else if (ExitCode != 0) {
|
||||
|
||||
Env.NumCrashes++;
|
||||
if (Options.IgnoreCrashes) {
|
||||
|
||||
std::ifstream In(Job->LogPath);
|
||||
std::string Line;
|
||||
while (std::getline(In, Line, '\n'))
|
||||
if (Line.find("ERROR:") != Line.npos ||
|
||||
Line.find("runtime error:") != Line.npos)
|
||||
Printf("%s\n", Line.c_str());
|
||||
|
||||
} else {
|
||||
|
||||
// And exit if we don't ignore this crash.
|
||||
Printf("INFO: log from the inner process:\n%s",
|
||||
FileToString(Job->LogPath).c_str());
|
||||
StopJobs();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stop if we are over the time budget.
|
||||
// This is not precise, since other threads are still running
|
||||
// and we will wait while joining them.
|
||||
// We also don't stop instantly: other jobs need to finish.
|
||||
if (Options.MaxTotalTimeSec > 0 &&
|
||||
Env.secondsSinceProcessStartUp() >= (size_t)Options.MaxTotalTimeSec) {
|
||||
|
||||
Printf("INFO: fuzzed for %zd seconds, wrapping up soon\n",
|
||||
Env.secondsSinceProcessStartUp());
|
||||
StopJobs();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (Env.NumRuns >= Options.MaxNumberOfRuns) {
|
||||
|
||||
Printf("INFO: fuzzed for %zd iterations, wrapping up soon\n",
|
||||
Env.NumRuns);
|
||||
StopJobs();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
FuzzQ.Push(Env.CreateNewJob(JobId++));
|
||||
|
||||
}
|
||||
|
||||
for (auto &T : Threads)
|
||||
T.join();
|
||||
|
||||
// The workers have terminated. Don't try to remove the directory before they
|
||||
// terminate to avoid a race condition preventing cleanup on Windows.
|
||||
RmDirRecursive(Env.TempDir);
|
||||
|
||||
// Use the exit code from the last child process.
|
||||
Printf("INFO: exiting: %d time: %zds\n", ExitCode,
|
||||
Env.secondsSinceProcessStartUp());
|
||||
exit(ExitCode);
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
24
custom_mutators/libfuzzer/FuzzerFork.h
Normal file
24
custom_mutators/libfuzzer/FuzzerFork.h
Normal file
@ -0,0 +1,24 @@
|
||||
//===- FuzzerFork.h - run fuzzing in sub-processes --------------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_FORK_H
|
||||
#define LLVM_FUZZER_FORK_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerOptions.h"
|
||||
#include "FuzzerRandom.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace fuzzer {
|
||||
void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
|
||||
const Vector<std::string> &Args,
|
||||
const Vector<std::string> &CorpusDirs, int NumJobs);
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_FORK_H
|
255
custom_mutators/libfuzzer/FuzzerIO.cpp
Normal file
255
custom_mutators/libfuzzer/FuzzerIO.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerUtil.h"
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static FILE *OutputFile = stderr;
|
||||
|
||||
long GetEpoch(const std::string &Path) {
|
||||
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St)) return 0; // Can't stat, be conservative.
|
||||
return St.st_mtime;
|
||||
|
||||
}
|
||||
|
||||
Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
|
||||
|
||||
std::ifstream T(Path, std::ios::binary);
|
||||
if (ExitOnError && !T) {
|
||||
|
||||
Printf("No such directory: %s; exiting\n", Path.c_str());
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
T.seekg(0, T.end);
|
||||
auto EndPos = T.tellg();
|
||||
if (EndPos < 0) return {};
|
||||
size_t FileLen = EndPos;
|
||||
if (MaxSize) FileLen = std::min(FileLen, MaxSize);
|
||||
|
||||
T.seekg(0, T.beg);
|
||||
Unit Res(FileLen);
|
||||
T.read(reinterpret_cast<char *>(Res.data()), FileLen);
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
std::string FileToString(const std::string &Path) {
|
||||
|
||||
std::ifstream T(Path, std::ios::binary);
|
||||
return std::string((std::istreambuf_iterator<char>(T)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
}
|
||||
|
||||
void CopyFileToErr(const std::string &Path) {
|
||||
|
||||
Printf("%s", FileToString(Path).c_str());
|
||||
|
||||
}
|
||||
|
||||
void WriteToFile(const Unit &U, const std::string &Path) {
|
||||
|
||||
WriteToFile(U.data(), U.size(), Path);
|
||||
|
||||
}
|
||||
|
||||
void WriteToFile(const std::string &Data, const std::string &Path) {
|
||||
|
||||
WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
|
||||
Path);
|
||||
|
||||
}
|
||||
|
||||
void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
|
||||
|
||||
return;
|
||||
|
||||
// Use raw C interface because this function may be called from a sig handler.
|
||||
FILE *Out = fopen(Path.c_str(), "wb");
|
||||
if (!Out) return;
|
||||
fwrite(Data, sizeof(Data[0]), Size, Out);
|
||||
fclose(Out);
|
||||
|
||||
}
|
||||
|
||||
void AppendToFile(const std::string &Data, const std::string &Path) {
|
||||
|
||||
return;
|
||||
|
||||
AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
|
||||
Path);
|
||||
|
||||
}
|
||||
|
||||
void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
|
||||
|
||||
return;
|
||||
|
||||
FILE *Out = fopen(Path.c_str(), "a");
|
||||
if (!Out) return;
|
||||
fwrite(Data, sizeof(Data[0]), Size, Out);
|
||||
fclose(Out);
|
||||
|
||||
}
|
||||
|
||||
void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V, long *Epoch,
|
||||
size_t MaxSize, bool ExitOnError) {
|
||||
|
||||
long E = Epoch ? *Epoch : 0;
|
||||
Vector<std::string> Files;
|
||||
ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/ true);
|
||||
size_t NumLoaded = 0;
|
||||
for (size_t i = 0; i < Files.size(); i++) {
|
||||
|
||||
auto &X = Files[i];
|
||||
if (Epoch && GetEpoch(X) < E) continue;
|
||||
NumLoaded++;
|
||||
if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
|
||||
Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
|
||||
auto S = FileToVector(X, MaxSize, ExitOnError);
|
||||
if (!S.empty()) V->push_back(S);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
|
||||
|
||||
Vector<std::string> Files;
|
||||
ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/ true);
|
||||
for (auto &File : Files)
|
||||
if (size_t Size = FileSize(File)) V->push_back({File, Size});
|
||||
|
||||
}
|
||||
|
||||
std::string DirPlusFile(const std::string &DirPath,
|
||||
const std::string &FileName) {
|
||||
|
||||
return DirPath + GetSeparator() + FileName;
|
||||
|
||||
}
|
||||
|
||||
void DupAndCloseStderr() {
|
||||
|
||||
int OutputFd = DuplicateFile(2);
|
||||
if (OutputFd >= 0) {
|
||||
|
||||
FILE *NewOutputFile = OpenFile(OutputFd, "w");
|
||||
if (NewOutputFile) {
|
||||
|
||||
OutputFile = NewOutputFile;
|
||||
if (EF->__sanitizer_set_report_fd)
|
||||
EF->__sanitizer_set_report_fd(
|
||||
reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
|
||||
DiscardOutput(2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CloseStdout() {
|
||||
|
||||
DiscardOutput(1);
|
||||
|
||||
}
|
||||
|
||||
void Printf(const char *Fmt, ...) {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, Fmt);
|
||||
vfprintf(OutputFile, Fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(OutputFile);
|
||||
|
||||
}
|
||||
|
||||
void VPrintf(bool Verbose, const char *Fmt, ...) {
|
||||
|
||||
return;
|
||||
if (!Verbose) return;
|
||||
va_list ap;
|
||||
va_start(ap, Fmt);
|
||||
vfprintf(OutputFile, Fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(OutputFile);
|
||||
|
||||
}
|
||||
|
||||
static bool MkDirRecursiveInner(const std::string &Leaf) {
|
||||
|
||||
// Prevent chance of potential infinite recursion
|
||||
if (Leaf == ".") return true;
|
||||
|
||||
const std::string &Dir = DirName(Leaf);
|
||||
|
||||
if (IsDirectory(Dir)) {
|
||||
|
||||
MkDir(Leaf);
|
||||
return IsDirectory(Leaf);
|
||||
|
||||
}
|
||||
|
||||
bool ret = MkDirRecursiveInner(Dir);
|
||||
if (!ret) {
|
||||
|
||||
// Give up early if a previous MkDir failed
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
MkDir(Leaf);
|
||||
return IsDirectory(Leaf);
|
||||
|
||||
}
|
||||
|
||||
bool MkDirRecursive(const std::string &Dir) {
|
||||
|
||||
if (Dir.empty()) return false;
|
||||
|
||||
if (IsDirectory(Dir)) return true;
|
||||
|
||||
return MkDirRecursiveInner(Dir);
|
||||
|
||||
}
|
||||
|
||||
void RmDirRecursive(const std::string &Dir) {
|
||||
|
||||
IterateDirRecursive(
|
||||
Dir, [](const std::string &Path) {},
|
||||
[](const std::string &Path) { RmDir(Path); },
|
||||
[](const std::string &Path) { RemoveFile(Path); });
|
||||
|
||||
}
|
||||
|
||||
std::string TempPath(const char *Prefix, const char *Extension) {
|
||||
|
||||
return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
|
||||
std::to_string(GetPid()) + Extension);
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
112
custom_mutators/libfuzzer/FuzzerIO.h
Normal file
112
custom_mutators/libfuzzer/FuzzerIO.h
Normal file
@ -0,0 +1,112 @@
|
||||
//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO interface.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_IO_H
|
||||
#define LLVM_FUZZER_IO_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
long GetEpoch(const std::string &Path);
|
||||
|
||||
Unit FileToVector(const std::string &Path, size_t MaxSize = 0,
|
||||
bool ExitOnError = true);
|
||||
|
||||
std::string FileToString(const std::string &Path);
|
||||
|
||||
void CopyFileToErr(const std::string &Path);
|
||||
|
||||
void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path);
|
||||
// Write Data.c_str() to the file without terminating null character.
|
||||
void WriteToFile(const std::string &Data, const std::string &Path);
|
||||
void WriteToFile(const Unit &U, const std::string &Path);
|
||||
|
||||
void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path);
|
||||
void AppendToFile(const std::string &Data, const std::string &Path);
|
||||
|
||||
void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
|
||||
long *Epoch, size_t MaxSize, bool ExitOnError);
|
||||
|
||||
// Returns "Dir/FileName" or equivalent for the current OS.
|
||||
std::string DirPlusFile(const std::string &DirPath,
|
||||
const std::string &FileName);
|
||||
|
||||
// Returns the name of the dir, similar to the 'dirname' utility.
|
||||
std::string DirName(const std::string &FileName);
|
||||
|
||||
// Returns path to a TmpDir.
|
||||
std::string TmpDir();
|
||||
|
||||
std::string TempPath(const char *Prefix, const char *Extension);
|
||||
|
||||
bool IsInterestingCoverageFile(const std::string &FileName);
|
||||
|
||||
void DupAndCloseStderr();
|
||||
|
||||
void CloseStdout();
|
||||
|
||||
void Printf(const char *Fmt, ...);
|
||||
void VPrintf(bool Verbose, const char *Fmt, ...);
|
||||
|
||||
// Print using raw syscalls, useful when printing at early init stages.
|
||||
void RawPrint(const char *Str);
|
||||
|
||||
// Platform specific functions:
|
||||
bool IsFile(const std::string &Path);
|
||||
bool IsDirectory(const std::string &Path);
|
||||
size_t FileSize(const std::string &Path);
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
Vector<std::string> *V, bool TopDir);
|
||||
|
||||
bool MkDirRecursive(const std::string &Dir);
|
||||
void RmDirRecursive(const std::string &Dir);
|
||||
|
||||
// Iterate files and dirs inside Dir, recursively.
|
||||
// Call DirPreCallback/DirPostCallback on dirs before/after
|
||||
// calling FileCallback on files.
|
||||
void IterateDirRecursive(const std::string &Dir,
|
||||
void (*DirPreCallback)(const std::string &Dir),
|
||||
void (*DirPostCallback)(const std::string &Dir),
|
||||
void (*FileCallback)(const std::string &Dir));
|
||||
|
||||
struct SizedFile {
|
||||
std::string File;
|
||||
size_t Size;
|
||||
bool operator<(const SizedFile &B) const { return Size < B.Size; }
|
||||
};
|
||||
|
||||
void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
|
||||
|
||||
char GetSeparator();
|
||||
bool IsSeparator(char C);
|
||||
// Similar to the basename utility: returns the file name w/o the dir prefix.
|
||||
std::string Basename(const std::string &Path);
|
||||
|
||||
FILE* OpenFile(int Fd, const char *Mode);
|
||||
|
||||
int CloseFile(int Fd);
|
||||
|
||||
int DuplicateFile(int Fd);
|
||||
|
||||
void RemoveFile(const std::string &Path);
|
||||
void RenameFile(const std::string &OldPath, const std::string &NewPath);
|
||||
|
||||
intptr_t GetHandleFromFd(int fd);
|
||||
|
||||
void MkDir(const std::string &Path);
|
||||
void RmDir(const std::string &Path);
|
||||
|
||||
const std::string &getDevNull();
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_IO_H
|
223
custom_mutators/libfuzzer/FuzzerIOPosix.cpp
Normal file
223
custom_mutators/libfuzzer/FuzzerIOPosix.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions implementation using Posix API.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerPlatform.h"
|
||||
#if LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
bool IsFile(const std::string &Path) {
|
||||
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St)) return false;
|
||||
return S_ISREG(St.st_mode);
|
||||
|
||||
}
|
||||
|
||||
bool IsDirectory(const std::string &Path) {
|
||||
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St)) return false;
|
||||
return S_ISDIR(St.st_mode);
|
||||
|
||||
}
|
||||
|
||||
size_t FileSize(const std::string &Path) {
|
||||
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St)) return 0;
|
||||
return St.st_size;
|
||||
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path) {
|
||||
|
||||
size_t Pos = Path.rfind(GetSeparator());
|
||||
if (Pos == std::string::npos) return Path;
|
||||
assert(Pos < Path.size());
|
||||
return Path.substr(Pos + 1);
|
||||
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
Vector<std::string> *V, bool TopDir) {
|
||||
|
||||
auto E = GetEpoch(Dir);
|
||||
if (Epoch)
|
||||
if (E && *Epoch >= E) return;
|
||||
|
||||
DIR *D = opendir(Dir.c_str());
|
||||
if (!D) {
|
||||
|
||||
Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str());
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
while (auto E = readdir(D)) {
|
||||
|
||||
std::string Path = DirPlusFile(Dir, E->d_name);
|
||||
if (E->d_type == DT_REG || E->d_type == DT_LNK ||
|
||||
(E->d_type == DT_UNKNOWN && IsFile(Path)))
|
||||
V->push_back(Path);
|
||||
else if ((E->d_type == DT_DIR ||
|
||||
(E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
|
||||
*E->d_name != '.')
|
||||
ListFilesInDirRecursive(Path, Epoch, V, false);
|
||||
|
||||
}
|
||||
|
||||
closedir(D);
|
||||
if (Epoch && TopDir) *Epoch = E;
|
||||
|
||||
}
|
||||
|
||||
void IterateDirRecursive(const std::string &Dir,
|
||||
void (*DirPreCallback)(const std::string &Dir),
|
||||
void (*DirPostCallback)(const std::string &Dir),
|
||||
void (*FileCallback)(const std::string &Dir)) {
|
||||
|
||||
DirPreCallback(Dir);
|
||||
DIR *D = opendir(Dir.c_str());
|
||||
if (!D) return;
|
||||
while (auto E = readdir(D)) {
|
||||
|
||||
std::string Path = DirPlusFile(Dir, E->d_name);
|
||||
if (E->d_type == DT_REG || E->d_type == DT_LNK ||
|
||||
(E->d_type == DT_UNKNOWN && IsFile(Path)))
|
||||
FileCallback(Path);
|
||||
else if ((E->d_type == DT_DIR ||
|
||||
(E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
|
||||
*E->d_name != '.')
|
||||
IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
|
||||
|
||||
}
|
||||
|
||||
closedir(D);
|
||||
DirPostCallback(Dir);
|
||||
|
||||
}
|
||||
|
||||
char GetSeparator() {
|
||||
|
||||
return '/';
|
||||
|
||||
}
|
||||
|
||||
bool IsSeparator(char C) {
|
||||
|
||||
return C == '/';
|
||||
|
||||
}
|
||||
|
||||
FILE *OpenFile(int Fd, const char *Mode) {
|
||||
|
||||
return fdopen(Fd, Mode);
|
||||
|
||||
}
|
||||
|
||||
int CloseFile(int fd) {
|
||||
|
||||
return close(fd);
|
||||
|
||||
}
|
||||
|
||||
int DuplicateFile(int Fd) {
|
||||
|
||||
return dup(Fd);
|
||||
|
||||
}
|
||||
|
||||
void RemoveFile(const std::string &Path) {
|
||||
|
||||
unlink(Path.c_str());
|
||||
|
||||
}
|
||||
|
||||
void RenameFile(const std::string &OldPath, const std::string &NewPath) {
|
||||
|
||||
rename(OldPath.c_str(), NewPath.c_str());
|
||||
|
||||
}
|
||||
|
||||
intptr_t GetHandleFromFd(int fd) {
|
||||
|
||||
return static_cast<intptr_t>(fd);
|
||||
|
||||
}
|
||||
|
||||
std::string DirName(const std::string &FileName) {
|
||||
|
||||
char *Tmp = new char[FileName.size() + 1];
|
||||
memcpy(Tmp, FileName.c_str(), FileName.size() + 1);
|
||||
std::string Res = dirname(Tmp);
|
||||
delete[] Tmp;
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
std::string TmpDir() {
|
||||
|
||||
if (auto Env = getenv("TMPDIR")) return Env;
|
||||
return "/tmp";
|
||||
|
||||
}
|
||||
|
||||
bool IsInterestingCoverageFile(const std::string &FileName) {
|
||||
|
||||
if (FileName.find("compiler-rt/lib/") != std::string::npos)
|
||||
return false; // sanitizer internal.
|
||||
if (FileName.find("/usr/lib/") != std::string::npos) return false;
|
||||
if (FileName.find("/usr/include/") != std::string::npos) return false;
|
||||
if (FileName == "<null>") return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void RawPrint(const char *Str) {
|
||||
|
||||
write(2, Str, strlen(Str));
|
||||
|
||||
}
|
||||
|
||||
void MkDir(const std::string &Path) {
|
||||
|
||||
mkdir(Path.c_str(), 0700);
|
||||
|
||||
}
|
||||
|
||||
void RmDir(const std::string &Path) {
|
||||
|
||||
rmdir(Path.c_str());
|
||||
|
||||
}
|
||||
|
||||
const std::string &getDevNull() {
|
||||
|
||||
static const std::string devNull = "/dev/null";
|
||||
return devNull;
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_POSIX
|
||||
|
513
custom_mutators/libfuzzer/FuzzerIOWindows.cpp
Normal file
513
custom_mutators/libfuzzer/FuzzerIOWindows.cpp
Normal file
@ -0,0 +1,513 @@
|
||||
//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions implementation for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerPlatform.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <io.h>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <windows.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_NORMAL) return true;
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) return false;
|
||||
|
||||
HANDLE FileHandle(CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
|
||||
|
||||
if (FileHandle == INVALID_HANDLE_VALUE) {
|
||||
|
||||
Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
DWORD FileType = GetFileType(FileHandle);
|
||||
|
||||
if (FileType == FILE_TYPE_UNKNOWN) {
|
||||
|
||||
Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
CloseHandle(FileHandle);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (FileType != FILE_TYPE_DISK) {
|
||||
|
||||
CloseHandle(FileHandle);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
CloseHandle(FileHandle);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool IsFile(const std::string &Path) {
|
||||
|
||||
DWORD Att = GetFileAttributesA(Path.c_str());
|
||||
|
||||
if (Att == INVALID_FILE_ATTRIBUTES) {
|
||||
|
||||
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), GetLastError());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return IsFile(Path, Att);
|
||||
|
||||
}
|
||||
|
||||
static bool IsDir(DWORD FileAttrs) {
|
||||
|
||||
if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
|
||||
return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
|
||||
|
||||
}
|
||||
|
||||
bool IsDirectory(const std::string &Path) {
|
||||
|
||||
DWORD Att = GetFileAttributesA(Path.c_str());
|
||||
|
||||
if (Att == INVALID_FILE_ATTRIBUTES) {
|
||||
|
||||
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), GetLastError());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return IsDir(Att);
|
||||
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path) {
|
||||
|
||||
size_t Pos = Path.find_last_of("/\\");
|
||||
if (Pos == std::string::npos) return Path;
|
||||
assert(Pos < Path.size());
|
||||
return Path.substr(Pos + 1);
|
||||
|
||||
}
|
||||
|
||||
size_t FileSize(const std::string &Path) {
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
|
||||
|
||||
DWORD LastError = GetLastError();
|
||||
if (LastError != ERROR_FILE_NOT_FOUND)
|
||||
Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), LastError);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
ULARGE_INTEGER size;
|
||||
size.HighPart = attr.nFileSizeHigh;
|
||||
size.LowPart = attr.nFileSizeLow;
|
||||
return size.QuadPart;
|
||||
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
Vector<std::string> *V, bool TopDir) {
|
||||
|
||||
auto E = GetEpoch(Dir);
|
||||
if (Epoch)
|
||||
if (E && *Epoch >= E) return;
|
||||
|
||||
std::string Path(Dir);
|
||||
assert(!Path.empty());
|
||||
if (Path.back() != '\\') Path.push_back('\\');
|
||||
Path.push_back('*');
|
||||
|
||||
// Get the first directory entry.
|
||||
WIN32_FIND_DATAA FindInfo;
|
||||
HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
|
||||
if (FindHandle == INVALID_HANDLE_VALUE) {
|
||||
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) return;
|
||||
Printf("No such file or directory: %s; exiting\n", Dir.c_str());
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
|
||||
|
||||
if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
|
||||
size_t FilenameLen = strlen(FindInfo.cFileName);
|
||||
if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
|
||||
(FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
|
||||
FindInfo.cFileName[1] == '.'))
|
||||
continue;
|
||||
|
||||
ListFilesInDirRecursive(FileName, Epoch, V, false);
|
||||
|
||||
} else if (IsFile(FileName, FindInfo.dwFileAttributes))
|
||||
|
||||
V->push_back(FileName);
|
||||
|
||||
} while (FindNextFileA(FindHandle, &FindInfo));
|
||||
|
||||
DWORD LastError = GetLastError();
|
||||
if (LastError != ERROR_NO_MORE_FILES)
|
||||
Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
|
||||
|
||||
FindClose(FindHandle);
|
||||
|
||||
if (Epoch && TopDir) *Epoch = E;
|
||||
|
||||
}
|
||||
|
||||
void IterateDirRecursive(const std::string &Dir,
|
||||
void (*DirPreCallback)(const std::string &Dir),
|
||||
void (*DirPostCallback)(const std::string &Dir),
|
||||
void (*FileCallback)(const std::string &Dir)) {
|
||||
|
||||
// TODO(metzman): Implement ListFilesInDirRecursive via this function.
|
||||
DirPreCallback(Dir);
|
||||
|
||||
DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
|
||||
if (!IsDir(DirAttrs)) return;
|
||||
|
||||
std::string TargetDir(Dir);
|
||||
assert(!TargetDir.empty());
|
||||
if (TargetDir.back() != '\\') TargetDir.push_back('\\');
|
||||
TargetDir.push_back('*');
|
||||
|
||||
WIN32_FIND_DATAA FindInfo;
|
||||
// Find the directory's first file.
|
||||
HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
|
||||
if (FindHandle == INVALID_HANDLE_VALUE) {
|
||||
|
||||
DWORD LastError = GetLastError();
|
||||
if (LastError != ERROR_FILE_NOT_FOUND) {
|
||||
|
||||
// If the directory isn't empty, then something abnormal is going on.
|
||||
Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
|
||||
LastError);
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
|
||||
DWORD PathAttrs = FindInfo.dwFileAttributes;
|
||||
if (IsDir(PathAttrs)) {
|
||||
|
||||
// Is Path the current directory (".") or the parent ("..")?
|
||||
if (strcmp(FindInfo.cFileName, ".") == 0 ||
|
||||
strcmp(FindInfo.cFileName, "..") == 0)
|
||||
continue;
|
||||
IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
|
||||
|
||||
} else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
|
||||
FileCallback(Path);
|
||||
|
||||
}
|
||||
|
||||
} while (FindNextFileA(FindHandle, &FindInfo));
|
||||
|
||||
DWORD LastError = GetLastError();
|
||||
if (LastError != ERROR_NO_MORE_FILES)
|
||||
Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
|
||||
LastError);
|
||||
|
||||
FindClose(FindHandle);
|
||||
DirPostCallback(Dir);
|
||||
|
||||
}
|
||||
|
||||
char GetSeparator() {
|
||||
|
||||
return '\\';
|
||||
|
||||
}
|
||||
|
||||
FILE *OpenFile(int Fd, const char *Mode) {
|
||||
|
||||
return _fdopen(Fd, Mode);
|
||||
|
||||
}
|
||||
|
||||
int CloseFile(int Fd) {
|
||||
|
||||
return _close(Fd);
|
||||
|
||||
}
|
||||
|
||||
int DuplicateFile(int Fd) {
|
||||
|
||||
return _dup(Fd);
|
||||
|
||||
}
|
||||
|
||||
void RemoveFile(const std::string &Path) {
|
||||
|
||||
_unlink(Path.c_str());
|
||||
|
||||
}
|
||||
|
||||
void RenameFile(const std::string &OldPath, const std::string &NewPath) {
|
||||
|
||||
rename(OldPath.c_str(), NewPath.c_str());
|
||||
|
||||
}
|
||||
|
||||
intptr_t GetHandleFromFd(int fd) {
|
||||
|
||||
return _get_osfhandle(fd);
|
||||
|
||||
}
|
||||
|
||||
bool IsSeparator(char C) {
|
||||
|
||||
return C == '\\' || C == '/';
|
||||
|
||||
}
|
||||
|
||||
// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseDrive(const std::string &FileName, const size_t Offset,
|
||||
bool Relative = true) {
|
||||
|
||||
if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':') return 0;
|
||||
if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
|
||||
|
||||
if (!Relative) // Accept relative path?
|
||||
return 0;
|
||||
else
|
||||
return 2;
|
||||
|
||||
}
|
||||
|
||||
return 3;
|
||||
|
||||
}
|
||||
|
||||
// Parse a file name, like: SomeFile.txt
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
|
||||
|
||||
size_t Pos = Offset;
|
||||
const size_t End = FileName.size();
|
||||
for (; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
|
||||
;
|
||||
return Pos - Offset;
|
||||
|
||||
}
|
||||
|
||||
// Parse a directory ending in separator, like: `SomeDir\`
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseDir(const std::string &FileName, const size_t Offset) {
|
||||
|
||||
size_t Pos = Offset;
|
||||
const size_t End = FileName.size();
|
||||
if (Pos >= End || IsSeparator(FileName[Pos])) return 0;
|
||||
for (; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
|
||||
;
|
||||
if (Pos >= End) return 0;
|
||||
++Pos; // Include separator.
|
||||
return Pos - Offset;
|
||||
|
||||
}
|
||||
|
||||
// Parse a servername and share, like: `SomeServer\SomeShare\`
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseServerAndShare(const std::string &FileName,
|
||||
const size_t Offset) {
|
||||
|
||||
size_t Pos = Offset, Res;
|
||||
if (!(Res = ParseDir(FileName, Pos))) return 0;
|
||||
Pos += Res;
|
||||
if (!(Res = ParseDir(FileName, Pos))) return 0;
|
||||
Pos += Res;
|
||||
return Pos - Offset;
|
||||
|
||||
}
|
||||
|
||||
// Parse the given Ref string from the position Offset, to exactly match the
|
||||
// given string Patt. Returns number of characters considered if successful.
|
||||
static size_t ParseCustomString(const std::string &Ref, size_t Offset,
|
||||
const char *Patt) {
|
||||
|
||||
size_t Len = strlen(Patt);
|
||||
if (Offset + Len > Ref.size()) return 0;
|
||||
return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
|
||||
|
||||
}
|
||||
|
||||
// Parse a location, like:
|
||||
// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C:
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseLocation(const std::string &FileName) {
|
||||
|
||||
size_t Pos = 0, Res;
|
||||
|
||||
if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
|
||||
|
||||
Pos += Res;
|
||||
if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
|
||||
|
||||
Pos += Res;
|
||||
if ((Res = ParseServerAndShare(FileName, Pos))) return Pos + Res;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if ((Res = ParseDrive(FileName, Pos, false))) return Pos + Res;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
|
||||
|
||||
++Pos;
|
||||
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
|
||||
|
||||
++Pos;
|
||||
if ((Res = ParseServerAndShare(FileName, Pos))) return Pos + Res;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return Pos;
|
||||
|
||||
}
|
||||
|
||||
if ((Res = ParseDrive(FileName, Pos))) return Pos + Res;
|
||||
|
||||
return Pos;
|
||||
|
||||
}
|
||||
|
||||
std::string DirName(const std::string &FileName) {
|
||||
|
||||
size_t LocationLen = ParseLocation(FileName);
|
||||
size_t DirLen = 0, Res;
|
||||
while ((Res = ParseDir(FileName, LocationLen + DirLen)))
|
||||
DirLen += Res;
|
||||
size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
|
||||
|
||||
if (LocationLen + DirLen + FileLen != FileName.size()) {
|
||||
|
||||
Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
if (DirLen) {
|
||||
|
||||
--DirLen; // Remove trailing separator.
|
||||
if (!FileLen) { // Path ended in separator.
|
||||
assert(DirLen);
|
||||
// Remove file name from Dir.
|
||||
while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
|
||||
--DirLen;
|
||||
if (DirLen) // Remove trailing separator.
|
||||
--DirLen;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!LocationLen) { // Relative path.
|
||||
if (!DirLen) return ".";
|
||||
return std::string(".\\").append(FileName, 0, DirLen);
|
||||
|
||||
}
|
||||
|
||||
return FileName.substr(0, LocationLen + DirLen);
|
||||
|
||||
}
|
||||
|
||||
std::string TmpDir() {
|
||||
|
||||
std::string Tmp;
|
||||
Tmp.resize(MAX_PATH + 1);
|
||||
DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
|
||||
if (Size == 0) {
|
||||
|
||||
Printf("Couldn't get Tmp path.\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
Tmp.resize(Size);
|
||||
return Tmp;
|
||||
|
||||
}
|
||||
|
||||
bool IsInterestingCoverageFile(const std::string &FileName) {
|
||||
|
||||
if (FileName.find("Program Files") != std::string::npos) return false;
|
||||
if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
|
||||
return false; // sanitizer internal.
|
||||
if (FileName == "<null>") return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void RawPrint(const char *Str) {
|
||||
|
||||
_write(2, Str, strlen(Str));
|
||||
|
||||
}
|
||||
|
||||
void MkDir(const std::string &Path) {
|
||||
|
||||
if (CreateDirectoryA(Path.c_str(), nullptr)) return;
|
||||
Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
|
||||
}
|
||||
|
||||
void RmDir(const std::string &Path) {
|
||||
|
||||
if (RemoveDirectoryA(Path.c_str())) return;
|
||||
Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
|
||||
}
|
||||
|
||||
const std::string &getDevNull() {
|
||||
|
||||
static const std::string devNull = "NUL";
|
||||
return devNull;
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
|
290
custom_mutators/libfuzzer/FuzzerInterceptors.cpp
Normal file
290
custom_mutators/libfuzzer/FuzzerInterceptors.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
//===-- FuzzerInterceptors.cpp --------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Intercept certain libc functions to aid fuzzing.
|
||||
// Linked only when other RTs that define their own interceptors are not linked.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerPlatform.h"
|
||||
|
||||
#if LIBFUZZER_LINUX
|
||||
|
||||
#define GET_CALLER_PC() __builtin_return_address(0)
|
||||
|
||||
#define PTR_TO_REAL(x) real_##x
|
||||
#define REAL(x) __interception::PTR_TO_REAL(x)
|
||||
#define FUNC_TYPE(x) x##_type
|
||||
#define DEFINE_REAL(ret_type, func, ...) \
|
||||
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
|
||||
namespace __interception { \
|
||||
\
|
||||
FUNC_TYPE(func) PTR_TO_REAL(func); \
|
||||
\
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <dlfcn.h> // for dlsym()
|
||||
|
||||
static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) {
|
||||
|
||||
void *addr = dlsym(RTLD_NEXT, name);
|
||||
if (!addr) {
|
||||
|
||||
// If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
|
||||
// later in the library search order than the DSO that we are trying to
|
||||
// intercept, which means that we cannot intercept this function. We still
|
||||
// want the address of the real definition, though, so look it up using
|
||||
// RTLD_DEFAULT.
|
||||
addr = dlsym(RTLD_DEFAULT, name);
|
||||
|
||||
// In case `name' is not loaded, dlsym ends up finding the actual wrapper.
|
||||
// We don't want to intercept the wrapper and have it point to itself.
|
||||
if (reinterpret_cast<uintptr_t>(addr) == wrapper_addr) addr = nullptr;
|
||||
|
||||
}
|
||||
|
||||
return addr;
|
||||
|
||||
}
|
||||
|
||||
static int FuzzerInited = 0;
|
||||
static bool FuzzerInitIsRunning;
|
||||
|
||||
static void fuzzerInit();
|
||||
|
||||
static void ensureFuzzerInited() {
|
||||
|
||||
assert(!FuzzerInitIsRunning);
|
||||
if (!FuzzerInited) { fuzzerInit(); }
|
||||
|
||||
}
|
||||
|
||||
static int internal_strcmp_strncmp(const char *s1, const char *s2, bool strncmp,
|
||||
size_t n) {
|
||||
|
||||
size_t i = 0;
|
||||
while (true) {
|
||||
|
||||
if (strncmp) {
|
||||
|
||||
if (i == n) break;
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
unsigned c1 = *s1;
|
||||
unsigned c2 = *s2;
|
||||
if (c1 != c2) return (c1 < c2) ? -1 : 1;
|
||||
if (c1 == 0) break;
|
||||
s1++;
|
||||
s2++;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int internal_strncmp(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
return internal_strcmp_strncmp(s1, s2, true, n);
|
||||
|
||||
}
|
||||
|
||||
static int internal_strcmp(const char *s1, const char *s2) {
|
||||
|
||||
return internal_strcmp_strncmp(s1, s2, false, 0);
|
||||
|
||||
}
|
||||
|
||||
static int internal_memcmp(const void *s1, const void *s2, size_t n) {
|
||||
|
||||
const uint8_t *t1 = static_cast<const uint8_t *>(s1);
|
||||
const uint8_t *t2 = static_cast<const uint8_t *>(s2);
|
||||
for (size_t i = 0; i < n; ++i, ++t1, ++t2)
|
||||
if (*t1 != *t2) return *t1 < *t2 ? -1 : 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static size_t internal_strlen(const char *s) {
|
||||
|
||||
size_t i = 0;
|
||||
while (s[i])
|
||||
i++;
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
static char *internal_strstr(const char *haystack, const char *needle) {
|
||||
|
||||
// This is O(N^2), but we are not using it in hot places.
|
||||
size_t len1 = internal_strlen(haystack);
|
||||
size_t len2 = internal_strlen(needle);
|
||||
if (len1 < len2) return nullptr;
|
||||
for (size_t pos = 0; pos <= len1 - len2; pos++) {
|
||||
|
||||
if (internal_memcmp(haystack + pos, needle, len2) == 0)
|
||||
return const_cast<char *>(haystack) + pos;
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Weak hooks forward-declared to avoid dependency on
|
||||
// <sanitizer/common_interface_defs.h>.
|
||||
void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
|
||||
const void *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
|
||||
const char *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
|
||||
const char *s2, int result);
|
||||
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, int result);
|
||||
void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result);
|
||||
void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result);
|
||||
void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
|
||||
const void *s2, size_t len2, void *result);
|
||||
|
||||
DEFINE_REAL(int, bcmp, const void *, const void *, size_t)
|
||||
DEFINE_REAL(int, memcmp, const void *, const void *, size_t)
|
||||
DEFINE_REAL(int, strncmp, const char *, const char *, size_t)
|
||||
DEFINE_REAL(int, strcmp, const char *, const char *)
|
||||
DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t)
|
||||
DEFINE_REAL(int, strcasecmp, const char *, const char *)
|
||||
DEFINE_REAL(char *, strstr, const char *, const char *)
|
||||
DEFINE_REAL(char *, strcasestr, const char *, const char *)
|
||||
DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t)
|
||||
|
||||
ATTRIBUTE_INTERFACE int bcmp(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
if (!FuzzerInited) return internal_memcmp(s1, s2, n);
|
||||
int result = REAL(bcmp)(s1, s2, n);
|
||||
__sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
|
||||
if (!FuzzerInited) return internal_memcmp(s1, s2, n);
|
||||
int result = REAL(memcmp)(s1, s2, n);
|
||||
__sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
if (!FuzzerInited) return internal_strncmp(s1, s2, n);
|
||||
int result = REAL(strncmp)(s1, s2, n);
|
||||
__sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) {
|
||||
|
||||
if (!FuzzerInited) return internal_strcmp(s1, s2);
|
||||
int result = REAL(strcmp)(s1, s2);
|
||||
__sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
ensureFuzzerInited();
|
||||
int result = REAL(strncasecmp)(s1, s2, n);
|
||||
__sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) {
|
||||
|
||||
ensureFuzzerInited();
|
||||
int result = REAL(strcasecmp)(s1, s2);
|
||||
__sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) {
|
||||
|
||||
if (!FuzzerInited) return internal_strstr(s1, s2);
|
||||
char *result = REAL(strstr)(s1, s2);
|
||||
__sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) {
|
||||
|
||||
ensureFuzzerInited();
|
||||
char *result = REAL(strcasestr)(s1, s2);
|
||||
__sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
ATTRIBUTE_INTERFACE
|
||||
void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) {
|
||||
|
||||
ensureFuzzerInited();
|
||||
void *result = REAL(memmem)(s1, len1, s2, len2);
|
||||
__sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2, result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((section(".preinit_array"),
|
||||
used)) static void (*__local_fuzzer_preinit)(void) = fuzzerInit;
|
||||
|
||||
} // extern "C"
|
||||
|
||||
static void fuzzerInit() {
|
||||
|
||||
assert(!FuzzerInitIsRunning);
|
||||
if (FuzzerInited) return;
|
||||
FuzzerInitIsRunning = true;
|
||||
|
||||
REAL(bcmp) = reinterpret_cast<memcmp_type>(
|
||||
getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp)));
|
||||
REAL(memcmp) = reinterpret_cast<memcmp_type>(
|
||||
getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp)));
|
||||
REAL(strncmp) = reinterpret_cast<strncmp_type>(
|
||||
getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp)));
|
||||
REAL(strcmp) = reinterpret_cast<strcmp_type>(
|
||||
getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp)));
|
||||
REAL(strncasecmp) = reinterpret_cast<strncasecmp_type>(
|
||||
getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp)));
|
||||
REAL(strcasecmp) = reinterpret_cast<strcasecmp_type>(
|
||||
getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp)));
|
||||
REAL(strstr) = reinterpret_cast<strstr_type>(
|
||||
getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr)));
|
||||
REAL(strcasestr) = reinterpret_cast<strcasestr_type>(
|
||||
getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr)));
|
||||
REAL(memmem) = reinterpret_cast<memmem_type>(
|
||||
getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem)));
|
||||
|
||||
FuzzerInitIsRunning = false;
|
||||
FuzzerInited = 1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
79
custom_mutators/libfuzzer/FuzzerInterface.h
Normal file
79
custom_mutators/libfuzzer/FuzzerInterface.h
Normal file
@ -0,0 +1,79 @@
|
||||
//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the interface between libFuzzer and the library being tested.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// NOTE: the libFuzzer interface is thin and in the majority of cases
|
||||
// you should not include this file into your target. In 95% of cases
|
||||
// all you need is to define the following function in your file:
|
||||
// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
// WARNING: keep the interface in C.
|
||||
|
||||
#ifndef LLVM_FUZZER_INTERFACE_H
|
||||
#define LLVM_FUZZER_INTERFACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// Define FUZZER_INTERFACE_VISIBILITY to set default visibility in a way that
|
||||
// doesn't break MSVC.
|
||||
#if defined(_WIN32)
|
||||
#define FUZZER_INTERFACE_VISIBILITY __declspec(dllexport)
|
||||
#else
|
||||
#define FUZZER_INTERFACE_VISIBILITY __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
// Mandatory user-provided target function.
|
||||
// Executes the code under test with [Data, Data+Size) as the input.
|
||||
// libFuzzer will invoke this function *many* times with different inputs.
|
||||
// Must return 0.
|
||||
FUZZER_INTERFACE_VISIBILITY int
|
||||
LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
// Optional user-provided initialization function.
|
||||
// If provided, this function will be called by libFuzzer once at startup.
|
||||
// It may read and modify argc/argv.
|
||||
// Must return 0.
|
||||
FUZZER_INTERFACE_VISIBILITY int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
|
||||
// Optional user-provided custom mutator.
|
||||
// Mutates raw data in [Data, Data+Size) inplace.
|
||||
// Returns the new size, which is not greater than MaxSize.
|
||||
// Given the same Seed produces the same mutation.
|
||||
FUZZER_INTERFACE_VISIBILITY size_t
|
||||
LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
|
||||
unsigned int Seed);
|
||||
|
||||
// Optional user-provided custom cross-over function.
|
||||
// Combines pieces of Data1 & Data2 together into Out.
|
||||
// Returns the new size, which is not greater than MaxOutSize.
|
||||
// Should produce the same mutation given the same Seed.
|
||||
FUZZER_INTERFACE_VISIBILITY size_t
|
||||
LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
|
||||
const uint8_t *Data2, size_t Size2, uint8_t *Out,
|
||||
size_t MaxOutSize, unsigned int Seed);
|
||||
|
||||
// Experimental, may go away in future.
|
||||
// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator.
|
||||
// Mutates raw data in [Data, Data+Size) inplace.
|
||||
// Returns the new size, which is not greater than MaxSize.
|
||||
FUZZER_INTERFACE_VISIBILITY size_t
|
||||
LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
#undef FUZZER_INTERFACE_VISIBILITY
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // LLVM_FUZZER_INTERFACE_H
|
173
custom_mutators/libfuzzer/FuzzerInternal.h
Normal file
173
custom_mutators/libfuzzer/FuzzerInternal.h
Normal file
@ -0,0 +1,173 @@
|
||||
//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the main class fuzzer::Fuzzer and most functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_INTERNAL_H
|
||||
#define LLVM_FUZZER_INTERNAL_H
|
||||
|
||||
#include "FuzzerDataFlowTrace.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerInterface.h"
|
||||
#include "FuzzerOptions.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerValueBitMap.h"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
class Fuzzer {
|
||||
public:
|
||||
|
||||
Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
|
||||
FuzzingOptions Options);
|
||||
~Fuzzer();
|
||||
void Loop(Vector<SizedFile> &CorporaFiles);
|
||||
void ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles);
|
||||
void MinimizeCrashLoop(const Unit &U);
|
||||
void RereadOutputCorpus(size_t MaxSize);
|
||||
|
||||
size_t secondsSinceProcessStartUp() {
|
||||
return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
|
||||
.count();
|
||||
}
|
||||
|
||||
bool TimedOut() {
|
||||
return Options.MaxTotalTimeSec > 0 &&
|
||||
secondsSinceProcessStartUp() >
|
||||
static_cast<size_t>(Options.MaxTotalTimeSec);
|
||||
}
|
||||
|
||||
size_t execPerSec() {
|
||||
size_t Seconds = secondsSinceProcessStartUp();
|
||||
return Seconds ? TotalNumberOfRuns / Seconds : 0;
|
||||
}
|
||||
|
||||
size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
|
||||
|
||||
static void StaticAlarmCallback();
|
||||
static void StaticCrashSignalCallback();
|
||||
static void StaticExitCallback();
|
||||
static void StaticInterruptCallback();
|
||||
static void StaticFileSizeExceedCallback();
|
||||
static void StaticGracefulExitCallback();
|
||||
|
||||
void ExecuteCallback(const uint8_t *Data, size_t Size);
|
||||
bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
|
||||
InputInfo *II = nullptr, bool ForceAddToCorpus = false,
|
||||
bool *FoundUniqFeatures = nullptr);
|
||||
|
||||
// Merge Corpora[1:] into Corpora[0].
|
||||
void Merge(const Vector<std::string> &Corpora);
|
||||
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
|
||||
MutationDispatcher &GetMD() { return MD; }
|
||||
void PrintFinalStats();
|
||||
void SetMaxInputLen(size_t MaxInputLen);
|
||||
void SetMaxMutationLen(size_t MaxMutationLen);
|
||||
void RssLimitCallback();
|
||||
|
||||
bool InFuzzingThread() const { return IsMyThread; }
|
||||
size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
|
||||
void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
|
||||
bool DuringInitialCorpusExecution);
|
||||
|
||||
void HandleMalloc(size_t Size);
|
||||
static void MaybeExitGracefully();
|
||||
std::string WriteToOutputCorpus(const Unit &U);
|
||||
|
||||
private:
|
||||
void AlarmCallback();
|
||||
void CrashCallback();
|
||||
void ExitCallback();
|
||||
void CrashOnOverwrittenData();
|
||||
void InterruptCallback();
|
||||
void MutateAndTestOne();
|
||||
void PurgeAllocator();
|
||||
void ReportNewCoverage(InputInfo *II, const Unit &U);
|
||||
void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
|
||||
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
|
||||
void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0,
|
||||
size_t Features = 0);
|
||||
void PrintStatusForNewUnit(const Unit &U, const char *Text);
|
||||
void CheckExitOnSrcPosOrItem();
|
||||
|
||||
static void StaticDeathCallback();
|
||||
void DumpCurrentUnit(const char *Prefix);
|
||||
void DeathCallback();
|
||||
|
||||
void AllocateCurrentUnitData();
|
||||
uint8_t *CurrentUnitData = nullptr;
|
||||
std::atomic<size_t> CurrentUnitSize;
|
||||
uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit.
|
||||
|
||||
bool GracefulExitRequested = false;
|
||||
|
||||
size_t TotalNumberOfRuns = 0;
|
||||
size_t NumberOfNewUnitsAdded = 0;
|
||||
|
||||
size_t LastCorpusUpdateRun = 0;
|
||||
|
||||
bool HasMoreMallocsThanFrees = false;
|
||||
size_t NumberOfLeakDetectionAttempts = 0;
|
||||
|
||||
system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now();
|
||||
|
||||
UserCallback CB;
|
||||
InputCorpus &Corpus;
|
||||
MutationDispatcher &MD;
|
||||
FuzzingOptions Options;
|
||||
DataFlowTrace DFT;
|
||||
|
||||
system_clock::time_point ProcessStartTime = system_clock::now();
|
||||
system_clock::time_point UnitStartTime, UnitStopTime;
|
||||
long TimeOfLongestUnitInSeconds = 0;
|
||||
long EpochOfLastReadOfOutputCorpus = 0;
|
||||
|
||||
size_t MaxInputLen = 0;
|
||||
size_t MaxMutationLen = 0;
|
||||
size_t TmpMaxMutationLen = 0;
|
||||
|
||||
Vector<uint32_t> UniqFeatureSetTmp;
|
||||
|
||||
// Need to know our own thread.
|
||||
static thread_local bool IsMyThread;
|
||||
};
|
||||
|
||||
struct ScopedEnableMsanInterceptorChecks {
|
||||
ScopedEnableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_enable_interceptor_checks)
|
||||
EF->__msan_scoped_enable_interceptor_checks();
|
||||
}
|
||||
~ScopedEnableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_disable_interceptor_checks)
|
||||
EF->__msan_scoped_disable_interceptor_checks();
|
||||
}
|
||||
};
|
||||
|
||||
struct ScopedDisableMsanInterceptorChecks {
|
||||
ScopedDisableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_disable_interceptor_checks)
|
||||
EF->__msan_scoped_disable_interceptor_checks();
|
||||
}
|
||||
~ScopedDisableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_enable_interceptor_checks)
|
||||
EF->__msan_scoped_enable_interceptor_checks();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_INTERNAL_H
|
1098
custom_mutators/libfuzzer/FuzzerLoop.cpp
Normal file
1098
custom_mutators/libfuzzer/FuzzerLoop.cpp
Normal file
File diff suppressed because it is too large
Load Diff
26
custom_mutators/libfuzzer/FuzzerMain.cpp
Normal file
26
custom_mutators/libfuzzer/FuzzerMain.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
//===- FuzzerMain.cpp - main() function and flags -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// main() and flags.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerPlatform.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// This function should be defined by the user.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
ATTRIBUTE_INTERFACE int main(int argc, char **argv) {
|
||||
|
||||
return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
|
||||
|
||||
}
|
||||
|
485
custom_mutators/libfuzzer/FuzzerMerge.cpp
Normal file
485
custom_mutators/libfuzzer/FuzzerMerge.cpp
Normal file
@ -0,0 +1,485 @@
|
||||
//===- FuzzerMerge.cpp - merging corpora ----------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Merging corpora.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCommand.h"
|
||||
#include "FuzzerMerge.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "FuzzerUtil.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
bool Merger::Parse(const std::string &Str, bool ParseCoverage) {
|
||||
|
||||
std::istringstream SS(Str);
|
||||
return Parse(SS, ParseCoverage);
|
||||
|
||||
}
|
||||
|
||||
void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
|
||||
|
||||
if (!Parse(IS, ParseCoverage)) {
|
||||
|
||||
Printf("MERGE: failed to parse the control file (unexpected error)\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The control file example:
|
||||
//
|
||||
// 3 # The number of inputs
|
||||
// 1 # The number of inputs in the first corpus, <= the previous number
|
||||
// file0
|
||||
// file1
|
||||
// file2 # One file name per line.
|
||||
// STARTED 0 123 # FileID, file size
|
||||
// FT 0 1 4 6 8 # FileID COV1 COV2 ...
|
||||
// COV 0 7 8 9 # FileID COV1 COV1
|
||||
// STARTED 1 456 # If FT is missing, the input crashed while processing.
|
||||
// STARTED 2 567
|
||||
// FT 2 8 9
|
||||
// COV 2 11 12
|
||||
bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
|
||||
|
||||
LastFailure.clear();
|
||||
std::string Line;
|
||||
|
||||
// Parse NumFiles.
|
||||
if (!std::getline(IS, Line, '\n')) return false;
|
||||
std::istringstream L1(Line);
|
||||
size_t NumFiles = 0;
|
||||
L1 >> NumFiles;
|
||||
if (NumFiles == 0 || NumFiles > 10000000) return false;
|
||||
|
||||
// Parse NumFilesInFirstCorpus.
|
||||
if (!std::getline(IS, Line, '\n')) return false;
|
||||
std::istringstream L2(Line);
|
||||
NumFilesInFirstCorpus = NumFiles + 1;
|
||||
L2 >> NumFilesInFirstCorpus;
|
||||
if (NumFilesInFirstCorpus > NumFiles) return false;
|
||||
|
||||
// Parse file names.
|
||||
Files.resize(NumFiles);
|
||||
for (size_t i = 0; i < NumFiles; i++)
|
||||
if (!std::getline(IS, Files[i].Name, '\n')) return false;
|
||||
|
||||
// Parse STARTED, FT, and COV lines.
|
||||
size_t ExpectedStartMarker = 0;
|
||||
const size_t kInvalidStartMarker = -1;
|
||||
size_t LastSeenStartMarker = kInvalidStartMarker;
|
||||
Vector<uint32_t> TmpFeatures;
|
||||
Set<uint32_t> PCs;
|
||||
while (std::getline(IS, Line, '\n')) {
|
||||
|
||||
std::istringstream ISS1(Line);
|
||||
std::string Marker;
|
||||
size_t N;
|
||||
ISS1 >> Marker;
|
||||
ISS1 >> N;
|
||||
if (Marker == "STARTED") {
|
||||
|
||||
// STARTED FILE_ID FILE_SIZE
|
||||
if (ExpectedStartMarker != N) return false;
|
||||
ISS1 >> Files[ExpectedStartMarker].Size;
|
||||
LastSeenStartMarker = ExpectedStartMarker;
|
||||
assert(ExpectedStartMarker < Files.size());
|
||||
ExpectedStartMarker++;
|
||||
|
||||
} else if (Marker == "FT") {
|
||||
|
||||
// FT FILE_ID COV1 COV2 COV3 ...
|
||||
size_t CurrentFileIdx = N;
|
||||
if (CurrentFileIdx != LastSeenStartMarker) return false;
|
||||
LastSeenStartMarker = kInvalidStartMarker;
|
||||
if (ParseCoverage) {
|
||||
|
||||
TmpFeatures.clear(); // use a vector from outer scope to avoid resizes.
|
||||
while (ISS1 >> N)
|
||||
TmpFeatures.push_back(N);
|
||||
std::sort(TmpFeatures.begin(), TmpFeatures.end());
|
||||
Files[CurrentFileIdx].Features = TmpFeatures;
|
||||
|
||||
}
|
||||
|
||||
} else if (Marker == "COV") {
|
||||
|
||||
size_t CurrentFileIdx = N;
|
||||
if (ParseCoverage)
|
||||
while (ISS1 >> N)
|
||||
if (PCs.insert(N).second) Files[CurrentFileIdx].Cov.push_back(N);
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (LastSeenStartMarker != kInvalidStartMarker)
|
||||
LastFailure = Files[LastSeenStartMarker].Name;
|
||||
|
||||
FirstNotProcessedFile = ExpectedStartMarker;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
size_t Merger::ApproximateMemoryConsumption() const {
|
||||
|
||||
size_t Res = 0;
|
||||
for (const auto &F : Files)
|
||||
Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]);
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
// Decides which files need to be merged (add those to NewFiles).
|
||||
// Returns the number of new features added.
|
||||
size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
|
||||
Set<uint32_t> * NewFeatures,
|
||||
const Set<uint32_t> &InitialCov, Set<uint32_t> *NewCov,
|
||||
Vector<std::string> *NewFiles) {
|
||||
|
||||
NewFiles->clear();
|
||||
assert(NumFilesInFirstCorpus <= Files.size());
|
||||
Set<uint32_t> AllFeatures = InitialFeatures;
|
||||
|
||||
// What features are in the initial corpus?
|
||||
for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
|
||||
|
||||
auto &Cur = Files[i].Features;
|
||||
AllFeatures.insert(Cur.begin(), Cur.end());
|
||||
|
||||
}
|
||||
|
||||
// Remove all features that we already know from all other inputs.
|
||||
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
||||
|
||||
auto & Cur = Files[i].Features;
|
||||
Vector<uint32_t> Tmp;
|
||||
std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
|
||||
AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
|
||||
Cur.swap(Tmp);
|
||||
|
||||
}
|
||||
|
||||
// Sort. Give preference to
|
||||
// * smaller files
|
||||
// * files with more features.
|
||||
std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(),
|
||||
[&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool {
|
||||
|
||||
if (a.Size != b.Size) return a.Size < b.Size;
|
||||
return a.Features.size() > b.Features.size();
|
||||
|
||||
});
|
||||
|
||||
// One greedy pass: add the file's features to AllFeatures.
|
||||
// If new features were added, add this file to NewFiles.
|
||||
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
||||
|
||||
auto &Cur = Files[i].Features;
|
||||
// Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(),
|
||||
// Files[i].Size, Cur.size());
|
||||
bool FoundNewFeatures = false;
|
||||
for (auto Fe : Cur) {
|
||||
|
||||
if (AllFeatures.insert(Fe).second) {
|
||||
|
||||
FoundNewFeatures = true;
|
||||
NewFeatures->insert(Fe);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (FoundNewFeatures) NewFiles->push_back(Files[i].Name);
|
||||
for (auto Cov : Files[i].Cov)
|
||||
if (InitialCov.find(Cov) == InitialCov.end()) NewCov->insert(Cov);
|
||||
|
||||
}
|
||||
|
||||
return NewFeatures->size();
|
||||
|
||||
}
|
||||
|
||||
Set<uint32_t> Merger::AllFeatures() const {
|
||||
|
||||
Set<uint32_t> S;
|
||||
for (auto &File : Files)
|
||||
S.insert(File.Features.begin(), File.Features.end());
|
||||
return S;
|
||||
|
||||
}
|
||||
|
||||
// Inner process. May crash if the target crashes.
|
||||
void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
|
||||
|
||||
Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str());
|
||||
Merger M;
|
||||
std::ifstream IF(CFPath);
|
||||
M.ParseOrExit(IF, false);
|
||||
IF.close();
|
||||
if (!M.LastFailure.empty())
|
||||
Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n",
|
||||
M.LastFailure.c_str());
|
||||
|
||||
Printf(
|
||||
"MERGE-INNER: %zd total files;"
|
||||
" %zd processed earlier; will process %zd files now\n",
|
||||
M.Files.size(), M.FirstNotProcessedFile,
|
||||
M.Files.size() - M.FirstNotProcessedFile);
|
||||
|
||||
std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
|
||||
Set<size_t> AllFeatures;
|
||||
auto PrintStatsWrapper = [this, &AllFeatures](const char *Where) {
|
||||
|
||||
this->PrintStats(Where, "\n", 0, AllFeatures.size());
|
||||
|
||||
};
|
||||
|
||||
Set<const TracePC::PCTableEntry *> AllPCs;
|
||||
for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
|
||||
|
||||
Fuzzer::MaybeExitGracefully();
|
||||
auto U = FileToVector(M.Files[i].Name);
|
||||
if (U.size() > MaxInputLen) {
|
||||
|
||||
U.resize(MaxInputLen);
|
||||
U.shrink_to_fit();
|
||||
|
||||
}
|
||||
|
||||
// Write the pre-run marker.
|
||||
OF << "STARTED " << i << " " << U.size() << "\n";
|
||||
OF.flush(); // Flush is important since Command::Execute may crash.
|
||||
// Run.
|
||||
TPC.ResetMaps();
|
||||
ExecuteCallback(U.data(), U.size());
|
||||
// Collect coverage. We are iterating over the files in this order:
|
||||
// * First, files in the initial corpus ordered by size, smallest first.
|
||||
// * Then, all other files, smallest first.
|
||||
// So it makes no sense to record all features for all files, instead we
|
||||
// only record features that were not seen before.
|
||||
Set<size_t> UniqFeatures;
|
||||
TPC.CollectFeatures([&](size_t Feature) {
|
||||
|
||||
if (AllFeatures.insert(Feature).second) UniqFeatures.insert(Feature);
|
||||
|
||||
});
|
||||
|
||||
TPC.UpdateObservedPCs();
|
||||
// Show stats.
|
||||
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
|
||||
PrintStatsWrapper("pulse ");
|
||||
if (TotalNumberOfRuns == M.NumFilesInFirstCorpus)
|
||||
PrintStatsWrapper("LOADED");
|
||||
// Write the post-run marker and the coverage.
|
||||
OF << "FT " << i;
|
||||
for (size_t F : UniqFeatures)
|
||||
OF << " " << F;
|
||||
OF << "\n";
|
||||
OF << "COV " << i;
|
||||
TPC.ForEachObservedPC([&](const TracePC::PCTableEntry *TE) {
|
||||
|
||||
if (AllPCs.insert(TE).second) OF << " " << TPC.PCTableEntryIdx(TE);
|
||||
|
||||
});
|
||||
|
||||
OF << "\n";
|
||||
OF.flush();
|
||||
|
||||
}
|
||||
|
||||
PrintStatsWrapper("DONE ");
|
||||
|
||||
}
|
||||
|
||||
static size_t WriteNewControlFile(const std::string & CFPath,
|
||||
const Vector<SizedFile> & OldCorpus,
|
||||
const Vector<SizedFile> & NewCorpus,
|
||||
const Vector<MergeFileInfo> &KnownFiles) {
|
||||
|
||||
std::unordered_set<std::string> FilesToSkip;
|
||||
for (auto &SF : KnownFiles)
|
||||
FilesToSkip.insert(SF.Name);
|
||||
|
||||
Vector<std::string> FilesToUse;
|
||||
auto MaybeUseFile = [=, &FilesToUse](std::string Name) {
|
||||
|
||||
if (FilesToSkip.find(Name) == FilesToSkip.end()) FilesToUse.push_back(Name);
|
||||
|
||||
};
|
||||
|
||||
for (auto &SF : OldCorpus)
|
||||
MaybeUseFile(SF.File);
|
||||
auto FilesToUseFromOldCorpus = FilesToUse.size();
|
||||
for (auto &SF : NewCorpus)
|
||||
MaybeUseFile(SF.File);
|
||||
|
||||
RemoveFile(CFPath);
|
||||
std::ofstream ControlFile(CFPath);
|
||||
ControlFile << FilesToUse.size() << "\n";
|
||||
ControlFile << FilesToUseFromOldCorpus << "\n";
|
||||
for (auto &FN : FilesToUse)
|
||||
ControlFile << FN << "\n";
|
||||
|
||||
if (!ControlFile) {
|
||||
|
||||
Printf("MERGE-OUTER: failed to write to the control file: %s\n",
|
||||
CFPath.c_str());
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
return FilesToUse.size();
|
||||
|
||||
}
|
||||
|
||||
// Outer process. Does not call the target code and thus should not fail.
|
||||
void CrashResistantMerge(const Vector<std::string> &Args,
|
||||
const Vector<SizedFile> & OldCorpus,
|
||||
const Vector<SizedFile> & NewCorpus,
|
||||
Vector<std::string> * NewFiles,
|
||||
const Set<uint32_t> & InitialFeatures,
|
||||
Set<uint32_t> * NewFeatures,
|
||||
const Set<uint32_t> &InitialCov, Set<uint32_t> *NewCov,
|
||||
const std::string &CFPath, bool V /*Verbose*/) {
|
||||
|
||||
if (NewCorpus.empty() && OldCorpus.empty()) return; // Nothing to merge.
|
||||
size_t NumAttempts = 0;
|
||||
Vector<MergeFileInfo> KnownFiles;
|
||||
if (FileSize(CFPath)) {
|
||||
|
||||
VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n",
|
||||
CFPath.c_str());
|
||||
Merger M;
|
||||
std::ifstream IF(CFPath);
|
||||
if (M.Parse(IF, /*ParseCoverage=*/true)) {
|
||||
|
||||
VPrintf(V,
|
||||
"MERGE-OUTER: control file ok, %zd files total,"
|
||||
" first not processed file %zd\n",
|
||||
M.Files.size(), M.FirstNotProcessedFile);
|
||||
if (!M.LastFailure.empty())
|
||||
VPrintf(V,
|
||||
"MERGE-OUTER: '%s' will be skipped as unlucky "
|
||||
"(merge has stumbled on it the last time)\n",
|
||||
M.LastFailure.c_str());
|
||||
if (M.FirstNotProcessedFile >= M.Files.size()) {
|
||||
|
||||
// Merge has already been completed with the given merge control file.
|
||||
if (M.Files.size() == OldCorpus.size() + NewCorpus.size()) {
|
||||
|
||||
VPrintf(
|
||||
V,
|
||||
"MERGE-OUTER: nothing to do, merge has been completed before\n");
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
// Number of input files likely changed, start merge from scratch, but
|
||||
// reuse coverage information from the given merge control file.
|
||||
VPrintf(
|
||||
V,
|
||||
"MERGE-OUTER: starting merge from scratch, but reusing coverage "
|
||||
"information from the given control file\n");
|
||||
KnownFiles = M.Files;
|
||||
|
||||
} else {
|
||||
|
||||
// There is a merge in progress, continue.
|
||||
NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
VPrintf(V, "MERGE-OUTER: bad control file, will overwrite it\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!NumAttempts) {
|
||||
|
||||
// The supplied control file is empty or bad, create a fresh one.
|
||||
VPrintf(V,
|
||||
"MERGE-OUTER: "
|
||||
"%zd files, %zd in the initial corpus, %zd processed earlier\n",
|
||||
OldCorpus.size() + NewCorpus.size(), OldCorpus.size(),
|
||||
KnownFiles.size());
|
||||
NumAttempts = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles);
|
||||
|
||||
}
|
||||
|
||||
// Execute the inner process until it passes.
|
||||
// Every inner process should execute at least one input.
|
||||
Command BaseCmd(Args);
|
||||
BaseCmd.removeFlag("merge");
|
||||
BaseCmd.removeFlag("fork");
|
||||
BaseCmd.removeFlag("collect_data_flow");
|
||||
for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) {
|
||||
|
||||
Fuzzer::MaybeExitGracefully();
|
||||
VPrintf(V, "MERGE-OUTER: attempt %zd\n", Attempt);
|
||||
Command Cmd(BaseCmd);
|
||||
Cmd.addFlag("merge_control_file", CFPath);
|
||||
Cmd.addFlag("merge_inner", "1");
|
||||
if (!V) {
|
||||
|
||||
Cmd.setOutputFile(getDevNull());
|
||||
Cmd.combineOutAndErr();
|
||||
|
||||
}
|
||||
|
||||
auto ExitCode = ExecuteCommand(Cmd);
|
||||
if (!ExitCode) {
|
||||
|
||||
VPrintf(V, "MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Read the control file and do the merge.
|
||||
Merger M;
|
||||
std::ifstream IF(CFPath);
|
||||
IF.seekg(0, IF.end);
|
||||
VPrintf(V, "MERGE-OUTER: the control file has %zd bytes\n",
|
||||
(size_t)IF.tellg());
|
||||
IF.seekg(0, IF.beg);
|
||||
M.ParseOrExit(IF, true);
|
||||
IF.close();
|
||||
VPrintf(V,
|
||||
"MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
|
||||
M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
|
||||
|
||||
M.Files.insert(M.Files.end(), KnownFiles.begin(), KnownFiles.end());
|
||||
M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles);
|
||||
VPrintf(V,
|
||||
"MERGE-OUTER: %zd new files with %zd new features added; "
|
||||
"%zd new coverage edges\n",
|
||||
NewFiles->size(), NewFeatures->size(), NewCov->size());
|
||||
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user