mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
4002 Commits
Author | SHA1 | Date | |
---|---|---|---|
90c6199e69 | |||
4d7c23e231 | |||
bbff0c88fa | |||
5543bd5b63 | |||
6a6387582c | |||
a772fbf1cd | |||
53327f9ee7 | |||
3101e9c88d | |||
fff8c49f7c | |||
b3fe3b8877 | |||
f5e9fe17f2 | |||
0daffb6283 | |||
32a0d6ac31 | |||
8151618276 | |||
9321a24e68 | |||
1e23a8d678 | |||
cc57cc5f46 | |||
4fa56f0696 | |||
766217e79e | |||
c55f7af657 | |||
939729e504 | |||
18fd97fc5f | |||
a705b1548f | |||
b13b8c7e55 | |||
212fe5b6f5 | |||
2c19750d08 | |||
9e8afcc615 | |||
6f03749c73 | |||
6e704e8a10 | |||
b5422c1a52 | |||
8d873357a3 | |||
8a2b140f40 | |||
c279750689 | |||
7fb2d90c49 | |||
ed2d474369 | |||
2d8050c397 | |||
50fcd60bc7 | |||
21215ac21c | |||
cd683ed253 | |||
3dd39fec90 | |||
b7cd6db08f | |||
4560ecc647 | |||
6df597213a | |||
6e818ed078 | |||
d346d07b63 | |||
bb627c7e58 | |||
9ec63d3f17 | |||
4fe572b80f | |||
3a3ef7b6b4 | |||
94999782f1 | |||
7cec158b0e | |||
b6a9e54c60 | |||
ec4ad161fc | |||
d16d8dbb85 | |||
fc3d7e821c | |||
37fff16a36 | |||
4ef12d7215 | |||
5bcbb2f59a | |||
1b2637545b | |||
d354ec2586 | |||
e1d5009229 | |||
fd4acc935e | |||
19b01d763a | |||
a09ab99534 | |||
ac565bfe51 | |||
6d878a375d | |||
f4b975d6ad | |||
161d763334 | |||
49df0af628 | |||
70312789fd | |||
8dbe87bdf6 | |||
458eb0813a | |||
f1bcd378a2 | |||
405382cbdd | |||
43db577dbb | |||
0662c5580b | |||
4a02118fda | |||
2a433f90c4 | |||
bf9a155418 | |||
6ec295db4e | |||
f7fb4495c4 | |||
dcf450ecba | |||
886e2ba770 | |||
7283205fe3 | |||
cca11b08b1 | |||
a8529de592 | |||
a6cf9bb336 | |||
5d5624b930 | |||
7da632065f | |||
000b16af16 | |||
046a9520f3 | |||
cda62bab08 | |||
7038e56da3 | |||
6a3877dcd3 | |||
c88b98d1c9 | |||
89ddd9998c | |||
28e6b96276 | |||
61e1c74d52 | |||
f348a35ec6 | |||
4057134d3c | |||
906bede108 | |||
1fcb52957e | |||
ec781af2c7 | |||
93b9832acd | |||
ae50a50677 | |||
d64cde8370 | |||
c6b77d2d05 | |||
600058aeab | |||
ff4d45eed2 | |||
56851fa499 | |||
cbac22d82b | |||
ba9323f14c | |||
98dc0d2649 | |||
58747f9f4f | |||
35153e9b49 | |||
c46f8c1f70 | |||
a6c0b5f766 | |||
7bcd4e2901 | |||
f3362007ed | |||
0c3feba3f6 | |||
ef5fd33120 | |||
74fcb365e9 | |||
ade8cdca55 | |||
35c23be973 | |||
2516324d3e | |||
8c1b0aba5f | |||
444e15cff0 | |||
dfff952f53 | |||
d2e256e73a | |||
581593ccab | |||
0978c08f4b | |||
b9f260452e | |||
8dd30947cb | |||
63504f7b7e | |||
a7340a1ac6 | |||
b8092c6227 | |||
706c2ac8e0 | |||
a4cb2414d5 | |||
f9a1e87635 | |||
e0aa411647 | |||
b9d2a87f03 | |||
3b9f4441e5 | |||
d57f0e3a1c | |||
48c878a76d | |||
c88f650bf8 | |||
fff8c5e0a8 | |||
c7b9171c10 | |||
cd95dfe1e7 | |||
d64dd7a952 | |||
63ee9df54f | |||
2d2d9b0b77 | |||
2449866f21 | |||
76c0940cee | |||
c69edc2b3c | |||
4bf08566ca | |||
c78a9e4b37 | |||
92fcef4520 | |||
a5ff9f1beb | |||
436f997d26 | |||
8f04269e17 | |||
280814c3a2 | |||
ddd9154e78 | |||
1474e2db23 | |||
2988dd206c | |||
fd07853550 | |||
0d50ee4947 | |||
43eca8203a | |||
36671ce799 | |||
f3b1c5c382 | |||
0897377b13 | |||
70a2077107 | |||
c5d899e0f5 | |||
2ecf77db7a | |||
55da5e3e02 | |||
0fbe5fb436 | |||
beb97cdc89 | |||
a38aafc5d0 | |||
d5a24acb21 | |||
a321d4102b | |||
a47c312252 | |||
bee3902062 | |||
96c802fce8 | |||
4b964e0a28 | |||
97225f1f6f | |||
e3a0ede91c | |||
db6947452c | |||
64368d4ba7 | |||
4096360791 | |||
753d5d74ff | |||
bdc7aa1a94 | |||
9cf45db7f9 | |||
3d1cc8ec57 | |||
02294d368a | |||
f9ca2cf989 | |||
d20d031141 | |||
b9799bbe1d | |||
07c3e47e6b | |||
7e54c8d7f6 | |||
8017f88614 | |||
5f6ff95e6a | |||
17e904eedf | |||
5b5dff4584 | |||
7665354405 | |||
67b294890e | |||
21c8b22571 | |||
97a1f89881 | |||
1a2da67ed0 | |||
b246de7891 | |||
eb74a7a800 | |||
c9539aa6b7 | |||
67293b298d | |||
c78762e690 | |||
d2e85cce50 | |||
6883605d13 | |||
de7370c0e9 | |||
8e86f7ad80 | |||
e5083fbf25 | |||
f677be5e86 | |||
14178141dc | |||
9e0370aa99 | |||
73f4d44ddc | |||
0aeb871ac9 | |||
2af9a634d6 | |||
64d9b7dd21 | |||
2210472784 | |||
6bd3c26cfb | |||
a5e551ab91 | |||
3b93729213 | |||
314c0357a7 | |||
ad3dba047f | |||
654bc7bf32 | |||
87b16c4460 | |||
8e75adfee5 | |||
109383f438 | |||
909e43fd55 | |||
95f47ac3a4 | |||
07c8024ef1 | |||
bb45398d0b | |||
bc286035e9 | |||
197c8845ee | |||
12c8d339b1 | |||
5864430d93 | |||
58e39ecd8f | |||
9e6e7e8fe8 | |||
bd1ceb42c4 | |||
1fe06d3856 | |||
d14a758f69 | |||
f66a4de18a | |||
1edb89be0f | |||
5a14ceb504 | |||
a3392baaaa | |||
bceae82754 | |||
c7908688b5 | |||
3844e79492 | |||
06d703bf66 | |||
5997a4fc09 | |||
a1458ea671 | |||
da2d4d8258 | |||
cdae3d3d03 | |||
dee64e74a8 | |||
59595a6897 | |||
d776d40669 | |||
2ef9ff4468 | |||
af900bca98 | |||
b669e77268 | |||
257cc1e82a | |||
d0af55e78f | |||
e40c0c2da1 | |||
9d50ae7468 | |||
fa63f2652d | |||
ccf739f880 | |||
47e22e8d8d | |||
a3fffac90c | |||
738246465d | |||
7b033367c2 | |||
3d28925c13 | |||
000c729095 | |||
72ca9b4684 | |||
8929da3391 | |||
fd077e86bd | |||
09458343c0 | |||
8b7a7b29c6 | |||
d0fa8dcba5 | |||
50af4654e3 | |||
82d0e4f210 | |||
84e55e7a1b | |||
ceb138cefe | |||
114605df53 | |||
340fc13de1 | |||
24551382d2 | |||
d982fddb18 | |||
7e0000021c | |||
de69ba01ba | |||
6c20d54b23 | |||
1b7aa1b63b | |||
b409d63fd3 | |||
6c274546c4 | |||
62d5bf5f41 | |||
069e61dfc6 | |||
2fd9629478 | |||
32be08d7b3 | |||
1d9a3d955c | |||
187ca8e18b | |||
70e2737222 | |||
7317a594fe | |||
c3b19f5bf8 | |||
6dc82e620b | |||
0618722e49 | |||
c695a031b8 | |||
be493f0aba | |||
b35e6deb09 | |||
dd96f01a16 | |||
361dd6e361 | |||
e2e7f3f0b5 | |||
26f1607766 | |||
6119c2eb5f | |||
c6e8314446 | |||
86452cc959 | |||
d0225c2c4d | |||
f4cc718fdc | |||
56882f3a49 | |||
094cd917b6 | |||
38f1394e3a | |||
e9d2f72382 | |||
b15fcde477 | |||
758bc770a8 | |||
caf282040f | |||
070c9923e2 | |||
765f3e5169 | |||
c9d066038f | |||
17b860d811 | |||
29dbe665a7 | |||
26b84e3521 | |||
aeb6883532 | |||
423c32969c | |||
97dbf5b671 | |||
6a134e4a26 | |||
dedeb01ffa | |||
3a0d4fe0d0 | |||
f112357e61 | |||
da65eef572 | |||
dde0538b48 | |||
39ad3b8946 | |||
976969dce5 | |||
8da5cba401 | |||
bd38fb6722 | |||
4d40afe54f | |||
5c705fbb92 | |||
a3f8fc5d1c | |||
3d830daa46 | |||
ade1d2819e | |||
4e402ba9fc | |||
48cef3c747 | |||
3b5fa3632b | |||
86a8ef168d | |||
b41ea92a67 | |||
2bd7206ec5 | |||
ec49c7fbf5 | |||
00e54565ef | |||
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 | |||
f0e08e6486 | |||
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 | |||
3782976528 | |||
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 | |||
41788950cc | |||
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 | |||
4183bc35b2 | |||
4700800770 | |||
9de74cce92 |
@ -10,7 +10,7 @@ AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
@ -52,7 +52,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
@ -72,7 +72,7 @@ IncludeCategories:
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
#
|
||||
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
# Copyright 2019 AFLplusplus Project. 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.
|
||||
@ -27,27 +27,33 @@ with open(".clang-format") as f:
|
||||
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
|
||||
if CLANG_FORMAT_BIN is None:
|
||||
p = subprocess.Popen(["clang-format", "--version"], stdout=subprocess.PIPE)
|
||||
o, _ = p.communicate()
|
||||
o = str(o, "utf-8")
|
||||
o = o[len("clang-format version "):].strip()
|
||||
o = o[:o.find(".")]
|
||||
o = int(o)
|
||||
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-10'], stdout=subprocess.PIPE) == 0:
|
||||
CLANG_FORMAT_BIN = 'clang-format-10'
|
||||
else:
|
||||
print ("clang-format 7 or above is needed. Aborted.")
|
||||
exit(1)
|
||||
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'
|
||||
|
||||
CLANG_FORMAT_BIN = "clang-format-11"
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
line = line.split(":")
|
||||
@ -63,26 +69,47 @@ def custom_format(filename):
|
||||
in_define = False
|
||||
last_line = None
|
||||
out = ""
|
||||
|
||||
|
||||
for line in src.split("\n"):
|
||||
if line.startswith("#"):
|
||||
if line.startswith("#define"):
|
||||
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):
|
||||
|
||||
if (
|
||||
"/*" in line
|
||||
and not line.strip().startswith("/*")
|
||||
and line.endswith("*/")
|
||||
and len(line) < (COLUMN_LIMIT - 2)
|
||||
):
|
||||
cmt_start = line.rfind("/*")
|
||||
line = line[:cmt_start] + " " * (COLUMN_LIMIT-2 - len(line)) + line[cmt_start:]
|
||||
line = (
|
||||
line[:cmt_start]
|
||||
+ " " * (COLUMN_LIMIT - 2 - len(line))
|
||||
+ line[cmt_start:]
|
||||
)
|
||||
|
||||
define_padding = 0
|
||||
if last_line is not None and in_define and last_line.endswith("\\"):
|
||||
last_line = last_line[:-1]
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n")+1:]))
|
||||
define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
|
||||
|
||||
if last_line is not None and last_line.strip().endswith("{") and line.strip() != "":
|
||||
if (
|
||||
last_line is not None
|
||||
and last_line.strip().endswith("{")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif last_line is not None and last_line.strip().startswith("}") and line.strip() != "":
|
||||
elif (
|
||||
last_line is not None
|
||||
and last_line.strip().startswith("}")
|
||||
and line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
elif line.strip().startswith("}") and last_line is not None and last_line.strip() != "":
|
||||
elif (
|
||||
line.strip().startswith("}")
|
||||
and last_line is not None
|
||||
and last_line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
|
||||
if not line.endswith("\\"):
|
||||
@ -91,14 +118,15 @@ def custom_format(filename):
|
||||
out += line + "\n"
|
||||
last_line = line
|
||||
|
||||
return (out)
|
||||
return out
|
||||
|
||||
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print ("Usage: ./format.py [-i] <filename>")
|
||||
print ()
|
||||
print (" The -i option, if specified, let the script to modify in-place")
|
||||
print (" the source files. By default the results are written to stdout.")
|
||||
print("Usage: ./format.py [-i] <filename>")
|
||||
print()
|
||||
print(" The -i option, if specified, let the script to modify in-place")
|
||||
print(" the source files. By default the results are written to stdout.")
|
||||
print()
|
||||
exit(1)
|
||||
|
||||
@ -114,4 +142,3 @@ for filename in args:
|
||||
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
|
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
github: AFLplusplus
|
||||
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
|
57
.gitignore
vendored
57
.gitignore
vendored
@ -1,28 +1,51 @@
|
||||
.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
|
||||
@ -31,9 +54,35 @@ 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
|
||||
as
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/unicorn
|
||||
unicorn_mode/unicorn-*
|
||||
unicorn_mode/*.tar.gz
|
||||
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
|
||||
|
12
.gitmodules
vendored
Normal file
12
.gitmodules
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
[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
|
||||
[submodule "custom_mutators/gramatron/json-c"]
|
||||
path = custom_mutators/gramatron/json-c
|
||||
url = https://github.com/json-c/json-c
|
11
.travis.yml
11
.travis.yml
@ -1,11 +0,0 @@
|
||||
language: c
|
||||
|
||||
env:
|
||||
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1
|
||||
|
||||
script:
|
||||
- make
|
||||
- ./afl-gcc ./test-instr.c -o test-instr
|
||||
- mkdir seeds; mkdir out
|
||||
- echo "" > seeds/nil_seed
|
||||
- timeout --preserve-status 5s ./afl-fuzz -i seeds -o out/ -- ./test-instr
|
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",
|
||||
]
|
@ -1 +0,0 @@
|
||||
Makefile
|
@ -1,14 +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-formatter
|
||||
make code-format
|
||||
```
|
||||
|
||||
This should be fine if you modified one of the file already present in the
|
||||
project, otherwise run:
|
||||
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
|
||||
-$(MAKE) -C utils/aflpp_driver
|
||||
|
||||
.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 src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.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
|
||||
-$(MAKE) -C frida_mode 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/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
|
||||
|
||||
%.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)
|
198
GNUmakefile.gcc_plugin
Normal file
198
GNUmakefile.gcc_plugin
Normal file
@ -0,0 +1,198 @@
|
||||
#
|
||||
# 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 ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
|
||||
.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-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
|
||||
$(CC) $(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) $(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) $(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
|
||||
|
||||
./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
|
526
GNUmakefile.llvm
Normal file
526
GNUmakefile.llvm
Normal file
@ -0,0 +1,526 @@
|
||||
# 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-2]\.|^3.[0-7]\.' && 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. Set LLVM_CONFIG to its path and retry.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(error llvm_mode only supports llvm from version 3.8 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 ./cmplog-switches-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
|
||||
|
||||
./cmplog-switches-pass.so: instrumentation/cmplog-switches-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
|
369
Makefile
369
Makefile
@ -1,357 +1,42 @@
|
||||
#
|
||||
# american fuzzy lop - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# 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
|
||||
#
|
||||
all:
|
||||
@echo trying to use GNU make...
|
||||
@gmake all || echo please install GNUmake
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
source-only:
|
||||
@gmake source-only
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^\#define VERSION ' include/config.h | cut -d '"' -f2)
|
||||
binary-only:
|
||||
@gmake binary-only
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
distrib:
|
||||
@gmake distrib
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
man:
|
||||
@gmake man
|
||||
|
||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
||||
install:
|
||||
@gmake install
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -Wno-unused-function
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
PYTHON_INCLUDE ?= /usr/include/python2.7
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
|
||||
ifeq "$(shell echo '\#include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 2>/dev/null && echo 1 || echo 0 )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON -I$(PYTHON_INCLUDE) -lpython2.7
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
|
||||
CFLAGS += -static
|
||||
LDFLAGS += -lm -lrt -lpthread -lz -lutil
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '\#include <sys/ipc.h>@\#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 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
|
||||
all: test_x86 test_shm test_python27 ready $(PROGS) afl-as test_build all_done
|
||||
|
||||
man: $(MANPAGES)
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
|
||||
performance-tests: performance-test
|
||||
test-performance: performance-test
|
||||
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, 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. for qemu_mode and unicorn_mode it means it deletes all downloads as well"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
|
||||
@echo "help: shows these build options :-)"
|
||||
@echo "=========================================="
|
||||
@echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
|
||||
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python27:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] Python 2.7 support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python27:
|
||||
@echo "[-] You seem to need to install the package python2.7-dev, but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
src/afl-common.o : src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
afl-fuzz: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(AFL_FUZZ_FILES) -D_AFL_DOCUMENT_MUTATIONS src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(LDFLAGS) $(PYFLAGS)
|
||||
document:
|
||||
@gmake document
|
||||
|
||||
deepclean:
|
||||
@gmake deepclean
|
||||
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i libdislocator/*.c
|
||||
./.custom-format.py -i libtokencap/*.c
|
||||
./.custom-format.py -i llvm_mode/*.c
|
||||
./.custom-format.py -i llvm_mode/*.h
|
||||
./.custom-format.py -i llvm_mode/*.cc
|
||||
./.custom-format.py -i gcc_plugin/*.c
|
||||
./.custom-format.py -i gcc_plugin/*.h
|
||||
./.custom-format.py -i gcc_plugin/*.cc
|
||||
./.custom-format.py -i qemu_mode/patches/*.h
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i unicorn_mode/patches/*.h
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
@gmake code-format
|
||||
|
||||
help:
|
||||
@gmake help
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
tests:
|
||||
@gmake tests
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS)
|
||||
./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
unit:
|
||||
@gmake unit
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
all_done: test_build
|
||||
@if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.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 src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.1.tar.xz afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast *.so unicorn_mode/24f55a7973278f20f0de21b904851d99d4716263.tar.gz *.8
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 unicorn_mode/unicorn *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
|
||||
distrib: all
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
binary-only: all
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
source-only: all
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date -I` "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -h 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
install: all $(MANPAGES)
|
||||
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
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
ifndef AFL_TRACE_PC
|
||||
if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
else
|
||||
if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
endif
|
||||
if [ -f afl-llvm-rt-32.o ]; then set -e; install -m 755 afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-llvm-rt-64.o ]; then set -e; install -m 755 afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f compare-transform-pass.so ]; then set -e; install -m 755 compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-compares-pass.so ]; then set -e; install -m 755 split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-switches-pass.so ]; then set -e; install -m 755 split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
|
||||
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 -D *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/README.md 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.md >~/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
|
57
TODO
57
TODO
@ -1,57 +0,0 @@
|
||||
|
||||
Roadmap 2.60:
|
||||
=============
|
||||
|
||||
afl-fuzz:
|
||||
- radamsa mutator
|
||||
- test the libmutator actually works and does not run infinite (need an example though)
|
||||
|
||||
gcc_plugin:
|
||||
- neverZero
|
||||
- laf-intel
|
||||
|
||||
qemu_mode:
|
||||
- update to 4.x (probably this will be skipped :( )
|
||||
- instrim for QEMU mode via static analysis (with r2pipe? or angr?)
|
||||
Idea: The static analyzer outputs a map in which each edge that must be
|
||||
skipped is marked with 1. QEMU loads it at startup in the parent process.
|
||||
|
||||
custom_mutators:
|
||||
- rip what Superion is doing into custom mutators for js, php, etc.
|
||||
|
||||
enhance test/test.sh script for checking if compcov features are working
|
||||
correctly (especially float splitting)
|
||||
|
||||
|
||||
The far away future:
|
||||
====================
|
||||
|
||||
Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges.
|
||||
At afl's default map that means ~16 collisions and ~3 wrappings.
|
||||
Solution #1: increase map size.
|
||||
every +1 decreases fuzzing speed by ~10% and halfs the collisions
|
||||
birthday paradox predicts collisions at this # of edges:
|
||||
mapsize => collisions
|
||||
2^16 = 302
|
||||
2^17 = 427
|
||||
2^18 = 603
|
||||
2^19 = 853
|
||||
2^20 = 1207
|
||||
2^21 = 1706
|
||||
2^22 = 2412
|
||||
2^23 = 3411
|
||||
2^24 = 4823
|
||||
Increasing the map is an easy solution but also not a good one.
|
||||
Solution #2: use dynamic map size and collision free basic block IDs
|
||||
This only works in llvm_mode and llvm >= 9 though
|
||||
A potential good future solution. Heiko/hexcoder follows this up
|
||||
Solution #3: write instruction pointers to a big shared map
|
||||
512kb/1MB shared map and the instrumented code writes the instruction
|
||||
pointer into the map. Map must be big enough but could be command line
|
||||
controlled.
|
||||
Good: complete coverage information, nothing is lost. choice of analysis
|
||||
impacts speed, but this can be decided by user options
|
||||
Neutral: a little bit slower but no loss of coverage
|
||||
Bad: completely changes how afl uses the map and the scheduling.
|
||||
Overall another very good solution, Marc Heuse/vanHauser follows this up
|
||||
|
38
TODO.md
Normal file
38
TODO.md
Normal file
@ -0,0 +1,38 @@
|
||||
# TODO list for AFL++
|
||||
|
||||
## Roadmap 3.00+
|
||||
|
||||
- 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()
|
||||
- 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).
|
964
afl-cmin
964
afl-cmin
@ -1,470 +1,542 @@
|
||||
#!/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 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.
|
||||
# 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 Michal Zalewski"
|
||||
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 UNICORN_MODE
|
||||
function getopt(argc, argv, options, thisopt, i)
|
||||
{
|
||||
if (length(options) == 0) # no options given
|
||||
return -1
|
||||
|
||||
while getopts "+i:o:f:m:t:eQUCh" 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_NO_FORKSRV: run target via execve instead of using the forkserver\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
|
||||
}
|
||||
|
||||
"h")
|
||||
;;
|
||||
function exists_and_is_executable(binarypath) {
|
||||
return 0 == system("test -f "binarypath" -a -x "binarypath)
|
||||
}
|
||||
|
||||
"i")
|
||||
IN_DIR="$OPTARG"
|
||||
;;
|
||||
BEGIN {
|
||||
print "corpus minimization tool for afl++ (awk version)\n"
|
||||
|
||||
"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
|
||||
;;
|
||||
"U")
|
||||
EXTRA_PAR="$EXTRA_PAR -U"
|
||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||
UNICORN_MODE=1
|
||||
;;
|
||||
"?")
|
||||
exit 1
|
||||
;;
|
||||
# defaults
|
||||
extra_par = ""
|
||||
AFL_CMIN_CRASHES_ONLY = ""
|
||||
|
||||
esac
|
||||
# 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
|
||||
|
||||
done
|
||||
if (!mem_limit) mem_limit = "none"
|
||||
if (!timeout) timeout = "none"
|
||||
|
||||
shift $((OPTIND-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]
|
||||
}
|
||||
|
||||
TARGET_BIN="$1"
|
||||
# sanity checks
|
||||
if (!prog_args[0] || !in_dir || !out_dir) usage()
|
||||
|
||||
if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
|
||||
target_bin = prog_args[0]
|
||||
|
||||
cat 1>&2 <<_EOF_
|
||||
Usage: $0 [ options ] -- /path/to/target_app [ ... ]
|
||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||
# handle this safely from an awk script.
|
||||
|
||||
Required parameters:
|
||||
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]
|
||||
|
||||
-i dir - input directory with the starting corpus
|
||||
-o dir - output directory for minimized files
|
||||
if (dir ~ /^(\/var)?\/tmp/) {
|
||||
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
delete dirlist
|
||||
}
|
||||
|
||||
Execution control settings:
|
||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||
# file name.
|
||||
|
||||
-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)
|
||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||
trace_dir = out_dir "/.traces"
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
# Check for obvious errors.
|
||||
|
||||
if (mem_limit && mem_limit != "none" && mem_limit < 5) {
|
||||
print "[-] Error: dangerously low memory limit." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (timeout && timeout != "none" && timeout < 10) {
|
||||
print "[-] Error: dangerously low timeout." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (target_bin && !exists_and_is_executable(target_bin)) {
|
||||
|
||||
"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 (!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
|
||||
}
|
||||
|
||||
#if (0 == system( "test -d "in_dir"/default" )) {
|
||||
# in_dir = in_dir "/default"
|
||||
#}
|
||||
#
|
||||
#if (0 == system( "test -d "in_dir"/queue" )) {
|
||||
# in_dir = in_dir "/queue"
|
||||
#}
|
||||
|
||||
system("rm -rf "trace_dir" 2>/dev/null");
|
||||
system("rm "out_dir"/id[:_]* 2>/dev/null")
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
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 \\) -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)
|
||||
infilesSmallToBigFull[i] = $0
|
||||
sub(/.*\//, "", $0)
|
||||
infilesSmallToBig[i] = $0
|
||||
infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i]
|
||||
infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
|
||||
i++
|
||||
}
|
||||
in_count = i
|
||||
|
||||
first_file = infilesSmallToBigFull[0]
|
||||
|
||||
Minimization settings:
|
||||
|
||||
-C - keep crashing inputs, reject everything else
|
||||
-e - solve for edge coverage only, ignore hit counts
|
||||
|
||||
For additional tips, please consult docs/README.
|
||||
|
||||
_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 "$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/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 (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
|
||||
# print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
|
||||
# exit 1
|
||||
#}
|
||||
|
||||
system(">\""in_dir"/.afl-cmin.test\"")
|
||||
if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) {
|
||||
cp_tool = "ln"
|
||||
} else {
|
||||
cp_tool = "cp"
|
||||
}
|
||||
system("rm -f \""in_dir"/.afl-cmin.test\"")
|
||||
|
||||
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)) {
|
||||
realfile = infilesSmallToBigMap[fn]
|
||||
system(cp_tool" \""in_dir"/"realfile"\" \""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
|
||||
|
493
afl-cmin.bash
Executable file
493
afl-cmin.bash
Executable file
@ -0,0 +1,493 @@
|
||||
#!/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_NO_FORKSRV: run target via execve instead of using the forkserver
|
||||
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
|
103
afl-plot
103
afl-plot
@ -1,9 +1,9 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop - Advanced Persistent Graphing
|
||||
# american fuzzy lop++ - Advanced Persistent Graphing
|
||||
# -------------------------------------------------
|
||||
#
|
||||
# Written by Michal Zalewski
|
||||
# Originally written by Michal Zalewski
|
||||
# Based on a design & prototype by Michael Rash.
|
||||
#
|
||||
# Copyright 2014, 2015 Google Inc. All rights reserved.
|
||||
@ -15,6 +15,10 @@
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
get_abs_path() {
|
||||
echo $(cd "`dirname "$1"`" && pwd)/"`basename "$1"`"
|
||||
}
|
||||
|
||||
echo "progress plotting utility for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
|
||||
@ -31,42 +35,53 @@ 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 "relative time in seconds" 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!"
|
||||
|
||||
|
@ -1,66 +1,131 @@
|
||||
#!/bin/sh
|
||||
test "$1" = "-h" && {
|
||||
echo afl-system-config by Marc Heuse
|
||||
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 "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
|
||||
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
|
||||
echo Error you need to be root to run this
|
||||
exit 1
|
||||
fi
|
||||
if [ "$PLATFORM" = "Linux" ] ; then
|
||||
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
|
||||
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"'
|
||||
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
|
||||
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 'sysctl hw.ibrs_disable=1'
|
||||
echo
|
||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
||||
{
|
||||
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
|
||||
echo 'System security features cannot be disabled on OpenBSD.'
|
||||
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
|
||||
echo
|
||||
echo It is recommended to enable unprivileged users to set cpu affinity
|
||||
echo to be able to use afl-gotcpu meaningfully.
|
||||
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
|
||||
{
|
||||
/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 We unload the default crash reporter here
|
||||
SL=/System/Library; PL=com.apple.ReportCrash
|
||||
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
|
||||
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
|
||||
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
|
||||
echo
|
||||
echo Also use AFL_TMPDIR to use a tmpfs for the input file
|
||||
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
|
||||
|
187
afl-whatsup
187
afl-whatsup
@ -1,11 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop - status check tool
|
||||
# --------------------------------------
|
||||
# american fuzzy lop++ - status check tool
|
||||
# ----------------------------------------
|
||||
#
|
||||
# Written by Michal Zalewski
|
||||
# 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,34 +18,44 @@
|
||||
# instances of afl-fuzz.
|
||||
#
|
||||
|
||||
echo "status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
|
||||
echo
|
||||
test "$1" = "-h" && {
|
||||
echo $0
|
||||
test "$1" = "-h" -o "$1" = "-hh" && {
|
||||
echo "Usage: $0 [-s] [-d] afl_output_directory"
|
||||
echo
|
||||
echo afl-whatsup has no command line options
|
||||
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
|
||||
|
||||
@ -59,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` || TMP=`mktemp -p /data/local/tmp .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
|
||||
@ -73,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"
|
||||
@ -81,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
|
||||
@ -107,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))
|
||||
@ -123,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
|
||||
@ -139,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
|
||||
@ -165,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
|
||||
|
@ -4,9 +4,10 @@ import os
|
||||
import sys
|
||||
import pefile
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("[afl-wine-trace] usage: wine-cov binary [args...]\n")
|
||||
print("[afl-wine-trace] usage: ./afl-wine-trace binary [args...]\n")
|
||||
exit(1)
|
||||
|
||||
if os.getenv("AFL_PATH"):
|
||||
@ -27,9 +28,9 @@ if not os.getenv("AFL_INST_LIBS"):
|
||||
os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
|
||||
|
||||
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
|
||||
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so")
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64"
|
||||
else:
|
||||
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so")
|
||||
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32"
|
||||
|
||||
if os.getenv("WINECOV_QEMU_PATH"):
|
||||
qemu_path = os.getenv("WINECOV_QEMU_PATH")
|
||||
@ -42,14 +43,20 @@ else:
|
||||
elif pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_I386"]:
|
||||
qemu_path += "i386"
|
||||
else:
|
||||
print ("[wine-cov] unsuppoted architecture\n")
|
||||
print ("[afl-wine-trace] unsuppoted architecture\n")
|
||||
exit(1)
|
||||
qemu_path = shutil.which(qemu_path)
|
||||
|
||||
if os.getenv("WINECOV_WINE_PATH"):
|
||||
wine_path = os.getenv("WINECOV_WINE_PATH")
|
||||
wine_path = None
|
||||
if os.getenv("AFL_WINE_PATH"):
|
||||
wine_path = os.getenv("AFL_WINE_PATH")
|
||||
else:
|
||||
wine_path = "/usr/lib/wine/wine"
|
||||
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"]:
|
||||
@ -58,4 +65,16 @@ else:
|
||||
print ("[afl-wine-trace] unsopported architecture\n")
|
||||
exit(1)
|
||||
|
||||
os.execve(qemu_path, [qemu_path, wine_path] + sys.argv[1:], os.environ)
|
||||
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)
|
||||
|
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",
|
||||
]
|
@ -1,2 +0,0 @@
|
||||
This is a simple example for the AFL_CUSTOM_MUTATOR_LIBRARY feature.
|
||||
For more information see docs/custom_mutator.txt
|
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.
|
@ -7,16 +7,18 @@ 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)
|
||||
Optionals parameters:
|
||||
seed Seed used by the PRNG (default: "RANDOM")
|
||||
verbose Verbosity (default: False)
|
||||
"""
|
||||
|
||||
def __init__(self, seed="RANDOM", verbose=False):
|
||||
@ -40,19 +42,24 @@ class XmlMutatorMin:
|
||||
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
|
||||
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):
|
||||
|
||||
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))
|
||||
tree = ET.parse(io.BytesIO(xml))
|
||||
except ET.ParseError:
|
||||
raise RuntimeError("XML isn't well-formed!")
|
||||
except LookupError as e:
|
||||
@ -61,34 +68,36 @@ class XmlMutatorMin:
|
||||
# Return a document wrapper
|
||||
return tree
|
||||
|
||||
def __exec_among (self, module, functions, min_times, max_times):
|
||||
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)):
|
||||
for i in xrange(random.randint(min_times, max_times)):
|
||||
# Function names are mangled because they are "private"
|
||||
getattr (module, "_XmlMutatorMin__" + random.choice(functions)) ()
|
||||
getattr(module, "_XmlMutatorMin__" + random.choice(functions))()
|
||||
|
||||
def __serialize_xml (self, tree):
|
||||
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)
|
||||
return ET.tostring(
|
||||
tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding
|
||||
)
|
||||
|
||||
def __ver (self, version):
|
||||
def __ver(self, version):
|
||||
|
||||
""" Helper for displaying lxml version numbers """
|
||||
|
||||
return ".".join(map(str, version))
|
||||
|
||||
def reset (self):
|
||||
|
||||
def reset(self):
|
||||
|
||||
""" Reset the mutator """
|
||||
|
||||
self.tree = deepcopy(self.input_tree)
|
||||
|
||||
def init_from_string (self, input_string):
|
||||
|
||||
def init_from_string(self, input_string):
|
||||
|
||||
""" Initialize the mutator from a XML string """
|
||||
|
||||
# Get a pointer to the top-element
|
||||
@ -97,15 +106,15 @@ class XmlMutatorMin:
|
||||
# Get a working copy
|
||||
self.tree = deepcopy(self.input_tree)
|
||||
|
||||
def save_to_string (self):
|
||||
|
||||
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):
|
||||
|
||||
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
|
||||
@ -119,7 +128,7 @@ class XmlMutatorMin:
|
||||
|
||||
# Pick a random element
|
||||
try:
|
||||
elem_id = random.randint (start, len(elems) - 1)
|
||||
elem_id = random.randint(start, len(elems) - 1)
|
||||
elem = elems[elem_id]
|
||||
except ValueError:
|
||||
# Should only occurs if "exclude_root_node = True"
|
||||
@ -127,8 +136,8 @@ class XmlMutatorMin:
|
||||
|
||||
return (elem_id, elem)
|
||||
|
||||
def __fuzz_attribute (self):
|
||||
|
||||
def __fuzz_attribute(self):
|
||||
|
||||
""" Fuzz (part of) an attribute value """
|
||||
|
||||
# Select a node to modify
|
||||
@ -144,23 +153,23 @@ class XmlMutatorMin:
|
||||
return
|
||||
|
||||
# Pick a random attribute
|
||||
rand_attrib_id = random.randint (0, len(attribs) - 1)
|
||||
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);
|
||||
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:
|
||||
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(','))
|
||||
value = random.choice(args.split(","))
|
||||
# Remove superfluous characters
|
||||
unclean_value = value
|
||||
value = value.strip(" ").strip("'")
|
||||
@ -169,49 +178,49 @@ class XmlMutatorMin:
|
||||
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_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_letter = (
|
||||
"P" * (25 * random.randrange(1, 100)),
|
||||
"%s%s%s%s%s%s",
|
||||
"foobar",
|
||||
)
|
||||
|
||||
choices_alnum = ( \
|
||||
"Abc123", \
|
||||
"020F0302020204030204", \
|
||||
"020F0302020204030204" * (random.randrange(5, 20)), \
|
||||
)
|
||||
choices_alnum = (
|
||||
"Abc123",
|
||||
"020F0302020204030204",
|
||||
"020F0302020204030204" * (random.randrange(5, 20)),
|
||||
)
|
||||
|
||||
# Fuzz the value
|
||||
if random.choice((True,False)) and value == "":
|
||||
if random.choice((True, False)) and value == "":
|
||||
|
||||
# Empty
|
||||
new_value = value
|
||||
|
||||
elif random.choice((True,False)) and value.isdigit():
|
||||
elif random.choice((True, False)) and value.isdigit():
|
||||
|
||||
# Numbers
|
||||
new_value = random.choice(choices_number)
|
||||
|
||||
elif random.choice((True,False)) and value.isalpha():
|
||||
elif random.choice((True, False)) and value.isalpha():
|
||||
|
||||
# Letters
|
||||
new_value = random.choice(choices_letter)
|
||||
|
||||
elif random.choice((True,False)) and value.isalnum():
|
||||
elif random.choice((True, False)) and value.isalnum():
|
||||
|
||||
# Alphanumeric
|
||||
new_value = random.choice(choices_alnum)
|
||||
@ -231,34 +240,37 @@ class XmlMutatorMin:
|
||||
|
||||
# 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))
|
||||
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):
|
||||
def __del_node_and_children(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random node and its children (i.e. delete a random tree) """
|
||||
"""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):
|
||||
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) """
|
||||
"""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):
|
||||
|
||||
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)
|
||||
(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")
|
||||
# Then we can't pick a element (given that "exclude_root_node = True")
|
||||
|
||||
# Is the document deep enough?
|
||||
if rand_elem is None:
|
||||
@ -269,20 +281,23 @@ class XmlMutatorMin:
|
||||
# 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))
|
||||
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 """
|
||||
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()
|
||||
@ -294,10 +309,10 @@ class XmlMutatorMin:
|
||||
# Reset the node
|
||||
rand_elem.clear()
|
||||
|
||||
def __del_attribute (self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random attribute from a random node """
|
||||
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()
|
||||
@ -312,20 +327,22 @@ class XmlMutatorMin:
|
||||
return
|
||||
|
||||
# Pick a random attribute
|
||||
rand_attrib_id = random.randint (0, len(attribs) - 1)
|
||||
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))
|
||||
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):
|
||||
|
||||
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)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Module containing functions shared between multiple AFL modules
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,26 +12,29 @@ 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)]
|
||||
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))
|
||||
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))
|
||||
|
||||
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)
|
||||
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
|
||||
|
379
custom_mutators/examples/example.c
Normal file
379
custom_mutators/examples/example.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
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
|
||||
* @return if the file contents was modified return 1 (True), 0 (False)
|
||||
* otherwise
|
||||
*/
|
||||
uint8_t 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 */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Example Python Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,92 +12,176 @@ 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)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
'''
|
||||
|
||||
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(buf)
|
||||
# Do something interesting with ret
|
||||
"""
|
||||
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 by Michal Zalewski
|
||||
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 by Michal Zalewski
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
'''
|
||||
"""
|
||||
Simple Chunk Cross-Over Replacement Module for AFLFuzz
|
||||
|
||||
@author: Christian Holler (:decoder)
|
||||
@ -12,48 +12,55 @@ 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)
|
||||
return 0
|
||||
|
||||
def fuzz(buf, add_buf):
|
||||
'''
|
||||
|
||||
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]
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ __seed__ = "RANDOM"
|
||||
__log__ = False
|
||||
__log_file__ = "wrapper.log"
|
||||
|
||||
# AFL functions
|
||||
|
||||
# AFL functions
|
||||
def log(text):
|
||||
"""
|
||||
Logger
|
||||
Logger
|
||||
"""
|
||||
|
||||
global __seed__
|
||||
@ -24,9 +24,10 @@ def log(text):
|
||||
with open(__log_file__, "a") as logf:
|
||||
logf.write("[%s] %s\n" % (__seed__, text))
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
"""
|
||||
|
||||
global __mutator__
|
||||
@ -37,17 +38,18 @@ def init(seed):
|
||||
|
||||
# Create a global mutation class
|
||||
try:
|
||||
__mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
|
||||
__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):
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
"""
|
||||
Called for each fuzzing iteration.
|
||||
Called for each fuzzing iteration.
|
||||
"""
|
||||
|
||||
global __mutator__
|
||||
global __mutator__
|
||||
|
||||
# Do we have a working mutator object?
|
||||
if __mutator__ is None:
|
||||
@ -62,7 +64,7 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
buf_str = str(buf)
|
||||
log("fuzz(): AFL buffer converted to a string")
|
||||
except:
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't convert AFL buffer to a string")
|
||||
|
||||
@ -70,29 +72,32 @@ def fuzz(buf, add_buf):
|
||||
if via_buffer:
|
||||
try:
|
||||
__mutator__.init_from_string(buf_str)
|
||||
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
||||
except:
|
||||
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
|
||||
log("fuzz(): Returning unmodified AFL buffer")
|
||||
return buf
|
||||
|
||||
# Sucessful initialization -> mutate
|
||||
try:
|
||||
__mutator__.mutate(max=5)
|
||||
log("fuzz(): Input mutated")
|
||||
except:
|
||||
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:
|
||||
except Exception:
|
||||
log("fuzz(): Can't convert mutated data to bytes => returning buf")
|
||||
return buf
|
||||
|
||||
@ -100,9 +105,9 @@ def fuzz(buf, add_buf):
|
||||
log("fuzz(): Returning %d bytes" % len(data))
|
||||
return data
|
||||
|
||||
# Main (for debug)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Main (for debug)
|
||||
if __name__ == "__main__":
|
||||
|
||||
__log__ = True
|
||||
__log_file__ = "/dev/stdout"
|
||||
@ -110,8 +115,9 @@ if __name__ == '__main__':
|
||||
|
||||
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_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/gramatron/JSONC_VERSION
Normal file
1
custom_mutators/gramatron/JSONC_VERSION
Normal file
@ -0,0 +1 @@
|
||||
af8dd4a307e7b837f9fa2959549548ace4afe08b
|
45
custom_mutators/gramatron/README.md
Normal file
45
custom_mutators/gramatron/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# GramaTron
|
||||
|
||||
Gramatron is a coverage-guided fuzzer that uses grammar automatons to perform
|
||||
grammar-aware fuzzing. Technical details about our framework are available
|
||||
in the [ISSTA'21 paper](https://nebelwelt.net/files/21ISSTA.pdf).
|
||||
The artifact to reproduce the experiments presented in the paper are present
|
||||
in `artifact/`. Instructions to run a sample campaign and incorporate new
|
||||
grammars is presented below:
|
||||
|
||||
# Compiling
|
||||
|
||||
Simply execute `./build_gramatron_mutator.sh`
|
||||
|
||||
# Running
|
||||
|
||||
You have to set the grammar file to use with `GRAMMATRON_AUTOMATION`:
|
||||
|
||||
```
|
||||
export AFL_DISABLE_TRIM=1
|
||||
export AFL_CUSTOM_MUTATOR_ONLY=1
|
||||
export AFL_CUSTOM_MUTATOR_LIBRARY=./gramatron.so
|
||||
export GRAMATRON_AUTOMATION=grammars/ruby/source_automata.json
|
||||
afl-fuzz -i in -o out -- ./target
|
||||
```
|
||||
|
||||
# Adding and testing a new grammar
|
||||
|
||||
- Specify in a JSON format for CFG. Examples are correspond `source.json` files
|
||||
- Run the automaton generation script (in `src/gramfuzz-mutator/preprocess`)
|
||||
which will place the generated automaton in the same folder.
|
||||
```
|
||||
./preprocess/prep_automaton.sh <grammar_file> <start_symbol> [stack_limit]
|
||||
|
||||
Eg. ./preprocess/prep_automaton.sh ~/grammars/ruby/source.json PROGRAM
|
||||
```
|
||||
- If the grammar has no self-embedding rules then you do not need to pass the
|
||||
stack limit parameter. However, if it does have self-embedding rules then you
|
||||
need to pass the stack limit parameter. We recommend starting with `5` and
|
||||
then increasing it if you need more complexity
|
||||
- To sanity-check that the automaton is generating inputs as expected you can use the `test` binary housed in `src/gramfuzz-mutator`
|
||||
```
|
||||
./test SanityCheck <automaton_file>
|
||||
|
||||
Eg. ./test SanityCheck ~/grammars/ruby/source_automata.json
|
||||
```
|
140
custom_mutators/gramatron/build_gramatron_mutator.sh
Executable file
140
custom_mutators/gramatron/build_gramatron_mutator.sh
Executable file
@ -0,0 +1,140 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# american fuzzy lop++ - gramatron 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>
|
||||
#
|
||||
# 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.
|
||||
|
||||
JSONC_VERSION="$(cat ./JSONC_VERSION)"
|
||||
JSONC_REPO="https://github.com/json-c/json-c"
|
||||
|
||||
echo "================================================="
|
||||
echo "Gramatron 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
|
||||
|
||||
test -z "$CC" && export CC=cc
|
||||
|
||||
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 json-c is checked out"
|
||||
|
||||
git status 1>/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[*] initializing json-c submodule"
|
||||
git submodule init || exit 1
|
||||
git submodule update ./json-c 2>/dev/null # ignore errors
|
||||
else
|
||||
echo "[*] cloning json-c"
|
||||
test -d json-c || {
|
||||
CNT=1
|
||||
while [ '!' -d json-c -a "$CNT" -lt 4 ]; do
|
||||
echo "Trying to clone json-c (attempt $CNT/3)"
|
||||
git clone "$JSONC_REPO"
|
||||
CNT=`expr "$CNT" + 1`
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
test -d json-c || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||
echo "[+] Got json-c."
|
||||
|
||||
cd "json-c" || exit 1
|
||||
echo "[*] Checking out $JSONC_VERSION"
|
||||
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
|
||||
git checkout "$JSONC_VERSION" || exit 1
|
||||
sh autogen.sh || exit 1
|
||||
export CFLAGS=-fPIC
|
||||
./configure --disable-shared || exit 1
|
||||
make || exit 1
|
||||
cd ..
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "[+] Json-c successfully prepared!"
|
||||
echo "[+] Builing gramatron now."
|
||||
$CC -O3 -g -fPIC -Wno-unused-result -Wl,--allow-multiple-definition -I../../include -o gramatron.so -shared -I. -I/prg/dev/include gramfuzz.c gramfuzz-helpers.c gramfuzz-mutators.c gramfuzz-util.c hashmap.c json-c/.libs/libjson-c.a || exit 1
|
||||
echo
|
||||
echo "[+] gramatron successfully built!"
|
336
custom_mutators/gramatron/gramfuzz-helpers.c
Normal file
336
custom_mutators/gramatron/gramfuzz-helpers.c
Normal file
@ -0,0 +1,336 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "afl-fuzz.h"
|
||||
#include "gramfuzz.h"
|
||||
|
||||
/*Slices from beginning till idx*/
|
||||
Array *slice(Array *input, int idx) {
|
||||
|
||||
// printf("\nSlice idx:%d", idx);
|
||||
terminal *origptr;
|
||||
terminal *term_ptr;
|
||||
Array * sliced = (Array *)malloc(sizeof(Array));
|
||||
initArray(sliced, input->size);
|
||||
// Populate dynamic array members
|
||||
if (idx == 0) { return sliced; }
|
||||
for (int x = 0; x < idx; x++) {
|
||||
|
||||
origptr = &input->start[x];
|
||||
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
|
||||
origptr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
return sliced;
|
||||
|
||||
}
|
||||
|
||||
/* Slices from idx till end*/
|
||||
Array *slice_inverse(Array *input, int idx) {
|
||||
|
||||
// printf("\nSlice idx:%d", idx);
|
||||
terminal *origptr;
|
||||
terminal *term_ptr;
|
||||
Array * sliced = (Array *)malloc(sizeof(Array));
|
||||
initArray(sliced, input->size);
|
||||
for (int x = idx; x < input->used; x++) {
|
||||
|
||||
origptr = &input->start[x];
|
||||
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
|
||||
origptr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
return sliced;
|
||||
|
||||
}
|
||||
|
||||
/*Carves with `start` included and `end` excluded*/
|
||||
Array *carve(Array *input, int start, int end) {
|
||||
|
||||
terminal *origptr;
|
||||
terminal *term_ptr;
|
||||
Array * sliced = (Array *)malloc(sizeof(Array));
|
||||
initArray(sliced, input->size);
|
||||
for (int x = start; x < end; x++) {
|
||||
|
||||
origptr = &input->start[x];
|
||||
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
|
||||
origptr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
return sliced;
|
||||
|
||||
}
|
||||
|
||||
/*Concats prefix + feature *mult*/
|
||||
void concatPrefixFeature(Array *prefix, Array *feature) {
|
||||
|
||||
// XXX: Currently we have hardcoded the multiplication threshold for adding
|
||||
// the recursive feature. Might want to fix it to choose a random number upper
|
||||
// bounded by a static value instead.
|
||||
terminal *featureptr;
|
||||
int len = rand_below(global_afl, RECUR_THRESHOLD);
|
||||
for (int x = 0; x < len; x++) {
|
||||
|
||||
for (int y = 0; y < feature->used; y++) {
|
||||
|
||||
featureptr = &feature->start[y];
|
||||
insertArray(prefix, featureptr->state, featureptr->symbol,
|
||||
featureptr->symbol_len, featureptr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void concatPrefixFeatureBench(Array *prefix, Array *feature) {
|
||||
|
||||
// XXX: Currently we have hardcoded the multiplication threshold for adding
|
||||
// the recursive feature. Might want to fix it to choose a random number upper
|
||||
// bounded by a static value instead.
|
||||
terminal *featureptr;
|
||||
int len =
|
||||
5; // 5 is the number of times we compare performing random recursion.
|
||||
for (int x = 0; x < len; x++) {
|
||||
|
||||
for (int y = 0; y < feature->used; y++) {
|
||||
|
||||
featureptr = &feature->start[y];
|
||||
insertArray(prefix, featureptr->state, featureptr->symbol,
|
||||
featureptr->symbol_len, featureptr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Array *spliceGF(Array *orig, Array *toSplice, int idx) {
|
||||
|
||||
terminal *toSplicePtr;
|
||||
terminal *tempPtr;
|
||||
// Iterate through the splice candidate from the `idx` till end
|
||||
for (int x = idx; x < toSplice->used; x++) {
|
||||
|
||||
toSplicePtr = &toSplice->start[x];
|
||||
insertArray(orig, toSplicePtr->state, toSplicePtr->symbol,
|
||||
toSplicePtr->symbol_len, toSplicePtr->trigger_idx);
|
||||
|
||||
}
|
||||
|
||||
return orig;
|
||||
|
||||
}
|
||||
|
||||
Array *gen_input(state *pda, Array *input) {
|
||||
|
||||
state * state_ptr;
|
||||
trigger * trigger_ptr;
|
||||
terminal *term_ptr;
|
||||
int offset = 0;
|
||||
int randval, error;
|
||||
// Generating an input for the first time
|
||||
if (input == NULL) {
|
||||
|
||||
input = (Array *)calloc(1, sizeof(Array));
|
||||
initArray(input, INIT_SIZE);
|
||||
curr_state = init_state;
|
||||
|
||||
}
|
||||
|
||||
while (curr_state != final_state) {
|
||||
|
||||
// Retrieving the state from the pda
|
||||
state_ptr = pda + curr_state;
|
||||
|
||||
// Get a random trigger
|
||||
randval = rand_below(global_afl, state_ptr->trigger_len);
|
||||
trigger_ptr = (state_ptr->ptr) + randval;
|
||||
|
||||
// Insert into the dynamic array
|
||||
insertArray(input, curr_state, trigger_ptr->term, trigger_ptr->term_len,
|
||||
randval);
|
||||
curr_state = trigger_ptr->dest;
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
}
|
||||
|
||||
Array *gen_input_count(state *pda, Array *input, int *mut_count) {
|
||||
|
||||
state * state_ptr;
|
||||
trigger * trigger_ptr;
|
||||
terminal *term_ptr;
|
||||
int offset = 0;
|
||||
int randval, error;
|
||||
// Generating an input for the first time
|
||||
if (input == NULL) {
|
||||
|
||||
input = (Array *)calloc(1, sizeof(Array));
|
||||
initArray(input, INIT_SIZE);
|
||||
curr_state = init_state;
|
||||
|
||||
}
|
||||
|
||||
while (curr_state != final_state) {
|
||||
|
||||
*mut_count += 1;
|
||||
// Retrieving the state from the pda
|
||||
state_ptr = pda + curr_state;
|
||||
|
||||
// Get a random trigger
|
||||
randval = rand_below(global_afl, state_ptr->trigger_len);
|
||||
trigger_ptr = (state_ptr->ptr) + randval;
|
||||
|
||||
// Insert into the dynamic array
|
||||
insertArray(input, curr_state, trigger_ptr->term, trigger_ptr->term_len,
|
||||
randval);
|
||||
curr_state = trigger_ptr->dest;
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
}
|
||||
|
||||
/*Creates a candidate from walk with state hashmap and
|
||||
* recursion hashmap
|
||||
*/
|
||||
|
||||
Candidate *gen_candidate(Array *input) {
|
||||
|
||||
terminal * term_ptr;
|
||||
IdxMap_new *idxmapPtr;
|
||||
// Declare the State Hash Table
|
||||
IdxMap_new *idxmapStart =
|
||||
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
|
||||
for (int x = 0; x < numstates; x++) {
|
||||
|
||||
idxmapPtr = &idxmapStart[x];
|
||||
utarray_new(idxmapPtr->nums, &ut_int_icd);
|
||||
|
||||
}
|
||||
|
||||
char * trigger;
|
||||
int state;
|
||||
char * key;
|
||||
Candidate *candidate = (Candidate *)malloc(sizeof(Candidate));
|
||||
candidate->walk = input;
|
||||
int offset = 0, error;
|
||||
|
||||
// Generate statemap for splicing
|
||||
while (offset < input->used) {
|
||||
|
||||
term_ptr = &input->start[offset];
|
||||
state = term_ptr->state;
|
||||
// char *statenum = state + 1;
|
||||
// int num = atoi(statenum);
|
||||
idxmapPtr = &idxmapStart[state];
|
||||
utarray_push_back(idxmapPtr->nums, &offset);
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
candidate->statemap = idxmapStart;
|
||||
return candidate;
|
||||
|
||||
}
|
||||
|
||||
char *get_state(char *trigger) {
|
||||
|
||||
// Get the state from transition
|
||||
int trigger_idx = 0;
|
||||
printf("\nTrigger:%s", trigger);
|
||||
char *state = (char *)malloc(sizeof(char) * 10);
|
||||
while (trigger[trigger_idx] != '_') {
|
||||
|
||||
state[trigger_idx] = trigger[trigger_idx];
|
||||
trigger_idx += 1;
|
||||
|
||||
}
|
||||
|
||||
printf("\nTrigger Idx:%d", trigger_idx);
|
||||
state[trigger_idx] = '\0';
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
void print_repr(Array *input, char *prefix) {
|
||||
|
||||
size_t offset = 0;
|
||||
terminal *term_ptr;
|
||||
char geninput[input->used * 100];
|
||||
if (!input->used) {
|
||||
|
||||
printf("\n=============");
|
||||
printf("\n%s:%s", prefix, "");
|
||||
printf("\n=============");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// This is done to create a null-terminated initial string
|
||||
term_ptr = &input->start[offset];
|
||||
strcpy(geninput, term_ptr->symbol);
|
||||
offset += 1;
|
||||
|
||||
while (offset < input->used) {
|
||||
|
||||
term_ptr = &input->start[offset];
|
||||
strcat(geninput, term_ptr->symbol);
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
printf("\n=============");
|
||||
printf("\n%s:%s", prefix, geninput);
|
||||
printf("\n=============");
|
||||
|
||||
}
|
||||
|
||||
// int main(int argc, char*argv[]) {
|
||||
|
||||
// char *mode;
|
||||
// if (argc == 1) {
|
||||
|
||||
// printf("\nUsage: ./gramfuzzer <mode>");
|
||||
// return -1;
|
||||
// }
|
||||
// if (argc >= 2) {
|
||||
|
||||
// mode = argv[1];
|
||||
// printf("\nMode:%s", mode);
|
||||
// }
|
||||
// if (! strcmp(mode, "Generate")) {
|
||||
|
||||
// GenInputBenchmark();
|
||||
// }
|
||||
// else if (! strcmp(mode, "RandomMutation")) {
|
||||
|
||||
// RandomMutationBenchmark();
|
||||
// }
|
||||
// else if (! strcmp(mode, "Splice")) {
|
||||
|
||||
// SpliceMutationBenchmark();
|
||||
// }
|
||||
// else if (! strcmp(mode, "Recursive")) {
|
||||
|
||||
// RandomRecursiveBenchmark();
|
||||
// }
|
||||
// else {
|
||||
|
||||
// printf("\nUnrecognized mode");
|
||||
// return -1;
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
247
custom_mutators/gramatron/gramfuzz-mutators.c
Normal file
247
custom_mutators/gramatron/gramfuzz-mutators.c
Normal file
@ -0,0 +1,247 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "afl-fuzz.h"
|
||||
#include "gramfuzz.h"
|
||||
|
||||
Array *performRandomMutation(state *pda, Array *input) {
|
||||
|
||||
terminal *term_ptr;
|
||||
// terminal *prev_ptr;
|
||||
Array *mutated;
|
||||
Array *sliced;
|
||||
|
||||
// Get offset at which to generate new input and slice it
|
||||
int idx = rand_below(global_afl, input->used);
|
||||
sliced = slice(input, idx);
|
||||
// print_repr(sliced, "Slice");
|
||||
|
||||
// prev_ptr = & input->start[idx - 1];
|
||||
// printf("\nState:%s Symbol:%s", prev_ptr->state, prev_ptr->symbol);
|
||||
// Reset current state to that of the slice's last member
|
||||
term_ptr = &input->start[idx];
|
||||
curr_state = term_ptr->state;
|
||||
// printf("\nState:%s Symbol:%s", curr_state, term_ptr->symbol);
|
||||
|
||||
// Set the next available cell to the one adjacent to this chosen point
|
||||
mutated = gen_input(pda, sliced);
|
||||
return mutated;
|
||||
|
||||
}
|
||||
|
||||
// Tries to perform splice operation between two automaton walks
|
||||
UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
|
||||
|
||||
Array *performSpliceOne(Array *originput, IdxMap_new *statemap_orig,
|
||||
Array *splicecand) {
|
||||
|
||||
UT_array * stateptr, *pairs;
|
||||
intpair_t ip;
|
||||
intpair_t *cand;
|
||||
|
||||
terminal *term_ptr;
|
||||
Array * prefix;
|
||||
int state;
|
||||
|
||||
// Initialize the dynamic holding the splice indice pairs
|
||||
utarray_new(pairs, &intpair_icd);
|
||||
// print_repr(originput, "Orig");
|
||||
// print_repr(splicecand, "SpliceCand");
|
||||
|
||||
// Iterate through the splice candidate identifying potential splice points
|
||||
// and pushing pair (orig_idx, splice_idx) to a dynamic array
|
||||
for (int x = 0; x < splicecand->used; x++) {
|
||||
|
||||
term_ptr = &splicecand->start[x];
|
||||
stateptr = statemap_orig[term_ptr->state].nums;
|
||||
int length = utarray_len(stateptr);
|
||||
if (length) {
|
||||
|
||||
int *splice_idx = (int *)utarray_eltptr(stateptr, rand_below(global_afl, length));
|
||||
ip.orig_idx = *splice_idx;
|
||||
ip.splice_idx = x;
|
||||
utarray_push_back(pairs, &ip);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Pick a random pair
|
||||
int length = utarray_len(pairs);
|
||||
cand = (intpair_t *)utarray_eltptr(pairs, rand_below(global_afl, length));
|
||||
// printf("\n Orig_idx:%d Splice_idx:%d", cand->orig_idx, cand->splice_idx);
|
||||
|
||||
// Perform the splicing
|
||||
prefix = slice(originput, cand->orig_idx);
|
||||
Array *spliced = spliceGF(prefix, splicecand, cand->splice_idx);
|
||||
// print_repr(spliced, "Spliced");
|
||||
//
|
||||
utarray_free(pairs);
|
||||
|
||||
return spliced;
|
||||
|
||||
}
|
||||
|
||||
UT_array **get_dupes(Array *input, int *recur_len) {
|
||||
|
||||
// Variables related to finding duplicates
|
||||
int offset = 0;
|
||||
int state;
|
||||
terminal * term_ptr;
|
||||
IdxMap_new *idxMapPtr;
|
||||
UT_array ** recurIdx;
|
||||
|
||||
// Declare the Recursive Map Table
|
||||
IdxMap_new *idxmapStart =
|
||||
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
|
||||
//
|
||||
// UT_array *(recurIdx[numstates]);
|
||||
recurIdx = malloc(sizeof(UT_array *) * numstates);
|
||||
|
||||
for (int x = 0; x < numstates; x++) {
|
||||
|
||||
idxMapPtr = &idxmapStart[x];
|
||||
utarray_new(idxMapPtr->nums, &ut_int_icd);
|
||||
|
||||
}
|
||||
|
||||
// Obtain frequency distribution of states
|
||||
while (offset < input->used) {
|
||||
|
||||
term_ptr = &input->start[offset];
|
||||
state = term_ptr->state;
|
||||
// int num = atoi(state + 1);
|
||||
idxMapPtr = &idxmapStart[state];
|
||||
utarray_push_back(idxMapPtr->nums, &offset);
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
// Retrieve the duplicated states
|
||||
offset = 0;
|
||||
while (offset < numstates) {
|
||||
|
||||
idxMapPtr = &idxmapStart[offset];
|
||||
int length = utarray_len(idxMapPtr->nums);
|
||||
if (length >= 2) {
|
||||
|
||||
recurIdx[*recur_len] = idxMapPtr->nums;
|
||||
*recur_len += 1;
|
||||
|
||||
}
|
||||
|
||||
// else {
|
||||
|
||||
// utarray_free(idxMapPtr->nums);
|
||||
// }
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
if (*recur_len) {
|
||||
|
||||
// Declare the return struct
|
||||
// We use this struct so that we save the reference to IdxMap_new and free
|
||||
// it after we have used it in doMult
|
||||
// Get_Dupes_Ret* getdupesret =
|
||||
// (Get_Dupes_Ret*)malloc(sizeof(Get_Dupes_Ret));
|
||||
return recurIdx;
|
||||
// getdupesret->idxmap = idxmapStart;
|
||||
// getdupesret->recurIdx = recurIdx;
|
||||
// return getdupesret;
|
||||
|
||||
} else {
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Array *doMult(Array *input, UT_array **recur, int recurlen) {
|
||||
|
||||
int offset = 0;
|
||||
int idx = rand_below(global_afl, recurlen);
|
||||
UT_array *recurMap = recur[idx];
|
||||
UT_array *recurPtr;
|
||||
Array * prefix;
|
||||
Array * postfix;
|
||||
Array * feature;
|
||||
|
||||
// Choose two indices to get the recursive feature
|
||||
int recurIndices = utarray_len(recurMap);
|
||||
int firstIdx = 0;
|
||||
int secondIdx = 0;
|
||||
getTwoIndices(recurMap, recurIndices, &firstIdx, &secondIdx);
|
||||
|
||||
// Perform the recursive mut
|
||||
// print_repr(input, "Orig");
|
||||
prefix = slice(input, firstIdx);
|
||||
// print_repr(prefix, "Prefix");
|
||||
if (firstIdx < secondIdx) {
|
||||
|
||||
feature = carve(input, firstIdx, secondIdx);
|
||||
|
||||
} else {
|
||||
|
||||
feature = carve(input, secondIdx, firstIdx);
|
||||
|
||||
}
|
||||
|
||||
// print_repr(feature, "Feature");
|
||||
concatPrefixFeature(prefix, feature);
|
||||
|
||||
// GC allocated structures
|
||||
free(feature->start);
|
||||
free(feature);
|
||||
// for(int x = 0; x < recurlen; x++) {
|
||||
|
||||
// utarray_free(recur[x]);
|
||||
// }
|
||||
// free(recur);
|
||||
// print_repr(prefix, "Concat");
|
||||
return spliceGF(prefix, input, secondIdx);
|
||||
|
||||
}
|
||||
|
||||
void getTwoIndices(UT_array *recur, int recurlen, int *firstIdx,
|
||||
int *secondIdx) {
|
||||
|
||||
int ArrayRecurIndices[recurlen];
|
||||
int offset = 0, *p;
|
||||
// Unroll into an array
|
||||
for (p = (int *)utarray_front(recur); p != NULL;
|
||||
p = (int *)utarray_next(recur, p)) {
|
||||
|
||||
ArrayRecurIndices[offset] = *p;
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
/*Source:
|
||||
* https://www.geeksforgeeks.org/shuffle-a-given-array-using-fisher-yates-shuffle-algorithm/
|
||||
*/
|
||||
for (int i = offset - 1; i > 0; i--) {
|
||||
|
||||
// Pick a random index from 0 to i
|
||||
int j = rand_below(global_afl, i + 1);
|
||||
|
||||
// Swap arr[i] with the element at random index
|
||||
swap(&ArrayRecurIndices[i], &ArrayRecurIndices[j]);
|
||||
|
||||
}
|
||||
|
||||
*firstIdx = ArrayRecurIndices[0];
|
||||
*secondIdx = ArrayRecurIndices[1];
|
||||
|
||||
}
|
||||
|
||||
void swap(int *a, int *b) {
|
||||
|
||||
int temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
|
||||
}
|
||||
|
268
custom_mutators/gramatron/gramfuzz-util.c
Normal file
268
custom_mutators/gramatron/gramfuzz-util.c
Normal file
@ -0,0 +1,268 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "afl-fuzz.h"
|
||||
#include "gramfuzz.h"
|
||||
#ifdef _GNU_SOURCE
|
||||
#undef _GNU_SOURCE
|
||||
#endif
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* Dynamic Array for adding to the input repr
|
||||
* */
|
||||
void initArray(Array *a, size_t initialSize) {
|
||||
|
||||
a->start = (terminal *)calloc(1, sizeof(terminal) * initialSize);
|
||||
a->used = 0;
|
||||
a->size = initialSize;
|
||||
a->inputlen = 0;
|
||||
|
||||
}
|
||||
|
||||
void insertArray(Array *a, int state, char *symbol, size_t symbol_len,
|
||||
int trigger_idx) {
|
||||
|
||||
// a->used is the number of used entries, because a->array[a->used++] updates
|
||||
// a->used only *after* the array has been accessed. Therefore a->used can go
|
||||
// up to a->size
|
||||
terminal *term_ptr;
|
||||
if (a->used == a->size) {
|
||||
|
||||
a->size = a->size * sizeof(terminal);
|
||||
a->start = (terminal *)realloc(a->start, a->size * sizeof(terminal));
|
||||
|
||||
}
|
||||
|
||||
// Add the element
|
||||
term_ptr = &a->start[a->used];
|
||||
term_ptr->state = state;
|
||||
term_ptr->symbol = symbol;
|
||||
term_ptr->symbol_len = symbol_len;
|
||||
term_ptr->trigger_idx = trigger_idx;
|
||||
|
||||
// Increment the pointer
|
||||
a->used += 1;
|
||||
a->inputlen += symbol_len;
|
||||
|
||||
}
|
||||
|
||||
void freeArray(Array *a) {
|
||||
|
||||
terminal *ptr;
|
||||
for (int x = 0; x < a->used; x++) {
|
||||
|
||||
ptr = &a->start[x];
|
||||
free(ptr);
|
||||
|
||||
}
|
||||
|
||||
a->start = NULL;
|
||||
a->used = a->size = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Dynamic array for adding indices of states/recursive features
|
||||
* Source:
|
||||
* https://stackoverflow.com/questions/3536153/c-dynamically-growing-array
|
||||
*/
|
||||
void initArrayIdx(IdxMap *a, size_t initialSize) {
|
||||
|
||||
a->array = (int *)malloc(initialSize * sizeof(int));
|
||||
a->used = 0;
|
||||
a->size = initialSize;
|
||||
|
||||
}
|
||||
|
||||
void insertArrayIdx(IdxMap *a, int idx) {
|
||||
|
||||
// a->used is the number of used entries, because a->array[a->used++] updates
|
||||
// a->used only *after* the array has been accessed. Therefore a->used can go
|
||||
// up to a->size
|
||||
if (a->used == a->size) {
|
||||
|
||||
a->size *= 2;
|
||||
a->array = (int *)realloc(a->array, a->size * sizeof(int));
|
||||
|
||||
}
|
||||
|
||||
a->array[a->used++] = idx;
|
||||
|
||||
}
|
||||
|
||||
void freeArrayIdx(IdxMap *a) {
|
||||
|
||||
free(a->array);
|
||||
a->array = NULL;
|
||||
a->used = a->size = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Dynamic array for adding potential splice points
|
||||
*/
|
||||
void initArraySplice(SpliceCandArray *a, size_t initialSize) {
|
||||
|
||||
a->start = (SpliceCand *)malloc(initialSize * sizeof(SpliceCand));
|
||||
a->used = 0;
|
||||
a->size = initialSize;
|
||||
|
||||
}
|
||||
|
||||
void insertArraySplice(SpliceCandArray *a, Candidate *candidate, int idx) {
|
||||
|
||||
// a->used is the number of used entries, because a->array[a->used++] updates
|
||||
// a->used only *after* the array has been accessed. Therefore a->used can go
|
||||
// up to a->size
|
||||
SpliceCand *candptr;
|
||||
if (a->used == a->size) {
|
||||
|
||||
a->size = a->size * sizeof(SpliceCand);
|
||||
a->start = (SpliceCand *)realloc(a->start, a->size * sizeof(SpliceCand));
|
||||
|
||||
}
|
||||
|
||||
// Add the element
|
||||
candptr = &a->start[a->used];
|
||||
candptr->splice_cand = candidate;
|
||||
candptr->idx = idx;
|
||||
a->used += 1;
|
||||
|
||||
}
|
||||
|
||||
void freeArraySplice(IdxMap *a) {
|
||||
|
||||
free(a->array);
|
||||
a->array = NULL;
|
||||
a->used = a->size = 0;
|
||||
|
||||
}
|
||||
|
||||
int fact(int n) {
|
||||
|
||||
int i, f = 1;
|
||||
for (i = 1; i <= n; i++) {
|
||||
|
||||
f *= i;
|
||||
|
||||
}
|
||||
|
||||
return f;
|
||||
|
||||
}
|
||||
|
||||
/* Uses the walk to create the input in-memory */
|
||||
u8 *unparse_walk(Array *input) {
|
||||
|
||||
terminal *term_ptr;
|
||||
int offset = 0;
|
||||
u8 * unparsed = (u8 *)malloc(input->inputlen + 1);
|
||||
term_ptr = &input->start[offset];
|
||||
strcpy(unparsed, term_ptr->symbol);
|
||||
offset += 1;
|
||||
while (offset < input->used) {
|
||||
|
||||
term_ptr = &input->start[offset];
|
||||
strcat(unparsed, term_ptr->symbol);
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
return unparsed;
|
||||
|
||||
}
|
||||
|
||||
/*Dump the input representation into a file*/
|
||||
void write_input(Array *input, u8 *fn) {
|
||||
|
||||
FILE *fp;
|
||||
// If file already exists, then skip creating the file
|
||||
if (access(fn, F_OK) != -1) { return; }
|
||||
|
||||
fp = fopen(fn, "wbx+");
|
||||
// If the input has already been flushed, then skip silently
|
||||
if (fp == NULL) {
|
||||
|
||||
fprintf(stderr, "\n File '%s' could not be open, exiting\n", fn);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
// Write the length parameters
|
||||
fwrite(&input->used, sizeof(size_t), 1, fp);
|
||||
fwrite(&input->size, sizeof(size_t), 1, fp);
|
||||
fwrite(&input->inputlen, sizeof(size_t), 1, fp);
|
||||
|
||||
// Write the dynamic array to file
|
||||
fwrite(input->start, input->size * sizeof(terminal), 1, fp);
|
||||
// printf("\nUsed:%zu Size:%zu Inputlen:%zu", input->used, input->size,
|
||||
// input->inputlen);
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
|
||||
Array *parse_input(state *pda, FILE *fp) {
|
||||
|
||||
terminal *term;
|
||||
state * state_ptr;
|
||||
trigger * trigger;
|
||||
int trigger_idx;
|
||||
Array * input = (Array *)calloc(1, sizeof(Array));
|
||||
|
||||
// Read the length parameters
|
||||
fread(&input->used, sizeof(size_t), 1, fp);
|
||||
fread(&input->size, sizeof(size_t), 1, fp);
|
||||
fread(&input->inputlen, sizeof(size_t), 1, fp);
|
||||
|
||||
terminal *start_ptr = (terminal *)calloc(input->size, sizeof(terminal));
|
||||
if (!start_ptr) {
|
||||
|
||||
fprintf(stderr, "alloc failed!\n");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
// Read the dynamic array to memory
|
||||
fread(start_ptr, input->size * sizeof(terminal), 1, fp);
|
||||
// Update the pointers to the terminals since they would have
|
||||
// changed
|
||||
int idx = 0;
|
||||
while (idx < input->used) {
|
||||
|
||||
terminal *term = &start_ptr[idx];
|
||||
// Find the state
|
||||
state_ptr = pda + term->state;
|
||||
// Find the trigger and update the terminal address
|
||||
trigger_idx = term->trigger_idx;
|
||||
trigger = (state_ptr->ptr) + trigger_idx;
|
||||
term->symbol = trigger->term;
|
||||
idx += 1;
|
||||
|
||||
}
|
||||
|
||||
input->start = start_ptr;
|
||||
// printf("\nUsed:%zu Size:%zu Inputlen:%zu", input->used, input->size,
|
||||
// input->inputlen);
|
||||
|
||||
return input;
|
||||
|
||||
}
|
||||
|
||||
// Read the input representation into memory
|
||||
Array *read_input(state *pda, u8 *fn) {
|
||||
|
||||
FILE *fp;
|
||||
fp = fopen(fn, "rb");
|
||||
if (fp == NULL) {
|
||||
|
||||
fprintf(stderr, "\n File '%s' does not exist, exiting\n", fn);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
Array *res = parse_input(pda, fp);
|
||||
fclose(fp);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
429
custom_mutators/gramatron/gramfuzz.c
Normal file
429
custom_mutators/gramatron/gramfuzz.c
Normal file
@ -0,0 +1,429 @@
|
||||
// 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>
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include "gramfuzz.h"
|
||||
|
||||
#define MUTATORS 4 // Specify the total number of mutators
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_state_t *afl;
|
||||
|
||||
u8 * mutator_buf;
|
||||
u8 * unparsed_input;
|
||||
Array *mutated_walk;
|
||||
Array *orig_walk;
|
||||
|
||||
IdxMap_new *statemap; // Keeps track of the statemap
|
||||
UT_array ** recurIdx;
|
||||
// Get_Dupes_Ret* getdupesret; // Recursive feature map
|
||||
int recurlen;
|
||||
|
||||
int mut_alloced;
|
||||
int orig_alloced;
|
||||
int mut_idx; // Signals the current mutator being used, used to cycle through
|
||||
// each mutator
|
||||
|
||||
unsigned int seed;
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
state *create_pda(u8 *automaton_file) {
|
||||
|
||||
struct json_object *parsed_json;
|
||||
state * pda;
|
||||
json_object * source_obj, *attr;
|
||||
int arraylen, ii, ii2, trigger_len, error;
|
||||
|
||||
printf("\n[GF] Automaton file passed:%s", automaton_file);
|
||||
// parsed_json =
|
||||
// json_object_from_file("./gramfuzz/php_gnf_processed_full.json");
|
||||
parsed_json = json_object_from_file(automaton_file);
|
||||
|
||||
// Getting final state
|
||||
source_obj = json_object_object_get(parsed_json, "final_state");
|
||||
printf("\t\nFinal=%s\n", json_object_get_string(source_obj));
|
||||
final_state = atoi(json_object_get_string(source_obj));
|
||||
|
||||
// Getting initial state
|
||||
source_obj = json_object_object_get(parsed_json, "init_state");
|
||||
init_state = atoi(json_object_get_string(source_obj));
|
||||
printf("\tInit=%s\n", json_object_get_string(source_obj));
|
||||
|
||||
// Getting number of states
|
||||
source_obj = json_object_object_get(parsed_json, "numstates");
|
||||
numstates = atoi(json_object_get_string(source_obj)) + 1;
|
||||
printf("\tNumStates=%d\n", numstates);
|
||||
|
||||
// Allocate state space for each pda state
|
||||
pda = (state *)calloc(atoi(json_object_get_string(source_obj)) + 1,
|
||||
sizeof(state));
|
||||
|
||||
// Getting PDA representation
|
||||
source_obj = json_object_object_get(parsed_json, "pda");
|
||||
enum json_type type;
|
||||
json_object_object_foreach(source_obj, key, val) {
|
||||
|
||||
state * state_ptr;
|
||||
trigger *trigger_ptr;
|
||||
int offset;
|
||||
|
||||
// Get the correct offset into the pda to store state information
|
||||
state_ptr = pda;
|
||||
offset = atoi(key);
|
||||
state_ptr += offset;
|
||||
// Store state string
|
||||
state_ptr->state_name = offset;
|
||||
|
||||
// Create trigger array of structs
|
||||
trigger_len = json_object_array_length(val);
|
||||
state_ptr->trigger_len = trigger_len;
|
||||
trigger_ptr = (trigger *)calloc(trigger_len, sizeof(trigger));
|
||||
state_ptr->ptr = trigger_ptr;
|
||||
|
||||
for (ii = 0; ii < trigger_len; ii++) {
|
||||
|
||||
json_object *obj = json_object_array_get_idx(val, ii);
|
||||
// Get all the trigger trigger attributes
|
||||
attr = json_object_array_get_idx(obj, 0);
|
||||
(trigger_ptr)->id = strdup(json_object_get_string(attr));
|
||||
|
||||
attr = json_object_array_get_idx(obj, 1);
|
||||
trigger_ptr->dest = atoi(json_object_get_string(attr));
|
||||
|
||||
attr = json_object_array_get_idx(obj, 2);
|
||||
if (!strcmp("\\n", json_object_get_string(attr))) {
|
||||
|
||||
trigger_ptr->term = strdup("\n");
|
||||
|
||||
} else {
|
||||
|
||||
trigger_ptr->term = strdup(json_object_get_string(attr));
|
||||
|
||||
}
|
||||
|
||||
trigger_ptr->term_len = strlen(trigger_ptr->term);
|
||||
trigger_ptr++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Delete the JSON object
|
||||
json_object_put(parsed_json);
|
||||
|
||||
return pda;
|
||||
|
||||
}
|
||||
|
||||
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
|
||||
|
||||
perror("mutator_buf alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
global_afl = afl; // dirty
|
||||
data->seed = seed;
|
||||
|
||||
data->mut_alloced = 0;
|
||||
data->orig_alloced = 0;
|
||||
data->mut_idx = 0;
|
||||
data->recurlen = 0;
|
||||
|
||||
// data->mutator_buf = NULL;
|
||||
// data->unparsed_input = NULL;
|
||||
// data->mutated_walk = NULL;
|
||||
// data->orig_walk = NULL;
|
||||
//
|
||||
// data->statemap = NULL; // Keeps track of the statemap
|
||||
// data->recur_idx = NULL; // Will keep track of recursive feature indices
|
||||
// u32 recur_len = 0; // The number of recursive features
|
||||
// data->mutator_buf = NULL;
|
||||
|
||||
char *automaton_file = getenv("GRAMATRON_AUTOMATION");
|
||||
if (automaton_file) {
|
||||
|
||||
pda = create_pda(automaton_file);
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr,
|
||||
"\nError: GrammaTron needs an automation json file set in "
|
||||
"AFL_GRAMATRON_AUTOMATON\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
size_t max_size) {
|
||||
|
||||
u8 *unparsed_input;
|
||||
|
||||
// Pick a mutator
|
||||
// int choice = rand() % MUTATORS;
|
||||
// data->mut_idx = 1;
|
||||
// GC old mutant
|
||||
if (data->mut_alloced) {
|
||||
|
||||
free(data->mutated_walk->start);
|
||||
free(data->mutated_walk);
|
||||
data->mut_alloced = 0;
|
||||
|
||||
};
|
||||
|
||||
// printf("\nChoice:%d", choice);
|
||||
|
||||
if (data->mut_idx == 0) { // Perform random mutation
|
||||
data->mutated_walk = performRandomMutation(pda, data->orig_walk);
|
||||
data->mut_alloced = 1;
|
||||
|
||||
} else if (data->mut_idx == 1 &&
|
||||
|
||||
data->recurlen) { // Perform recursive mutation
|
||||
data->mutated_walk =
|
||||
doMult(data->orig_walk, data->recurIdx, data->recurlen);
|
||||
data->mut_alloced = 1;
|
||||
|
||||
} else if (data->mut_idx == 2) { // Perform splice mutation
|
||||
|
||||
// we cannot use the supplied splice data so choose a new random file
|
||||
u32 tid = rand_below(global_afl, data->afl->queued_paths);
|
||||
struct queue_entry *q = data->afl->queue_buf[tid];
|
||||
|
||||
// Read the input representation for the splice candidate
|
||||
u8 * automaton_fn = alloc_printf("%s.aut", q->fname);
|
||||
Array *spliceCandidate = read_input(pda, automaton_fn);
|
||||
|
||||
if (spliceCandidate) {
|
||||
|
||||
data->mutated_walk =
|
||||
performSpliceOne(data->orig_walk, data->statemap, spliceCandidate);
|
||||
data->mut_alloced = 1;
|
||||
free(spliceCandidate->start);
|
||||
free(spliceCandidate);
|
||||
|
||||
} else {
|
||||
|
||||
data->mutated_walk = gen_input(pda, NULL);
|
||||
data->mut_alloced = 1;
|
||||
|
||||
}
|
||||
|
||||
ck_free(automaton_fn);
|
||||
|
||||
} else { // Generate an input from scratch
|
||||
|
||||
data->mutated_walk = gen_input(pda, NULL);
|
||||
data->mut_alloced = 1;
|
||||
|
||||
}
|
||||
|
||||
// Cycle to the next mutator
|
||||
if (data->mut_idx == MUTATORS - 1)
|
||||
data->mut_idx =
|
||||
0; // Wrap around if we have reached end of the mutator list
|
||||
else
|
||||
data->mut_idx += 1;
|
||||
|
||||
// Unparse the mutated automaton walk
|
||||
if (data->unparsed_input) { free(data->unparsed_input); }
|
||||
data->unparsed_input = unparse_walk(data->mutated_walk);
|
||||
*out_buf = data->unparsed_input;
|
||||
|
||||
return data->mutated_walk->inputlen;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the automaton-based representation for the corresponding input
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
u8 afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
// get the filename
|
||||
u8 * automaton_fn, *unparsed_input;
|
||||
Array *new_input;
|
||||
s32 fd;
|
||||
|
||||
automaton_fn = alloc_printf("%s.aut", filename_new_queue);
|
||||
// Check if this method is being called during initialization
|
||||
|
||||
// fprintf(stderr, "new: %s, old: %s, auto: %s\n",
|
||||
// filename_new_queue,filename_orig_queue,automaton_fn);
|
||||
|
||||
if (filename_orig_queue) {
|
||||
|
||||
write_input(data->mutated_walk, automaton_fn);
|
||||
|
||||
} else {
|
||||
|
||||
new_input = gen_input(pda, NULL);
|
||||
write_input(new_input, automaton_fn);
|
||||
|
||||
// Update the placeholder file
|
||||
if (unlink(filename_new_queue)) {
|
||||
|
||||
PFATAL("Unable to delete '%s'", filename_new_queue);
|
||||
|
||||
}
|
||||
|
||||
unparsed_input = unparse_walk(new_input);
|
||||
fd = open(filename_new_queue, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) { PFATAL("Failed to update file '%s'", filename_new_queue); }
|
||||
int written = write(fd, unparsed_input, new_input->inputlen + 1);
|
||||
close(fd);
|
||||
|
||||
free(new_input->start);
|
||||
free(new_input);
|
||||
free(unparsed_input);
|
||||
|
||||
}
|
||||
|
||||
ck_free(automaton_fn);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the corresponding tree representation for the candidate that is to be
|
||||
* mutated
|
||||
*
|
||||
* @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) {
|
||||
|
||||
// get the filename
|
||||
u8 * automaton_fn = alloc_printf("%s.aut", filename);
|
||||
IdxMap_new *statemap_ptr;
|
||||
terminal * term_ptr;
|
||||
int state;
|
||||
|
||||
// TODO: I don't think we need to update pointers when reading back
|
||||
// Probably build two different versions of read_input one for flushing
|
||||
// inputs to disk and the other that
|
||||
if (data->orig_alloced) {
|
||||
|
||||
free(data->orig_walk->start);
|
||||
free(data->orig_walk);
|
||||
data->orig_alloced = 0;
|
||||
|
||||
}
|
||||
|
||||
if (data->statemap) {
|
||||
|
||||
for (int x = 0; x < numstates; x++) {
|
||||
|
||||
utarray_free(data->statemap[x].nums);
|
||||
|
||||
}
|
||||
|
||||
free(data->statemap);
|
||||
|
||||
}
|
||||
|
||||
if (data->recurIdx) {
|
||||
|
||||
data->recurlen = 0;
|
||||
free(data->recurIdx);
|
||||
|
||||
}
|
||||
|
||||
data->orig_walk = read_input(pda, automaton_fn);
|
||||
data->orig_alloced = 1;
|
||||
|
||||
// Create statemap for the fuzz candidate
|
||||
IdxMap_new *statemap_start =
|
||||
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
|
||||
for (int x = 0; x < numstates; x++) {
|
||||
|
||||
statemap_ptr = &statemap_start[x];
|
||||
utarray_new(statemap_ptr->nums, &ut_int_icd);
|
||||
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
while (offset < data->orig_walk->used) {
|
||||
|
||||
term_ptr = &data->orig_walk->start[offset];
|
||||
state = term_ptr->state;
|
||||
statemap_ptr = &statemap_start[state];
|
||||
utarray_push_back(statemap_ptr->nums, &offset);
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
data->statemap = statemap_start;
|
||||
|
||||
// Create recursive feature map (if it exists)
|
||||
data->recurIdx = malloc(sizeof(UT_array *) * numstates);
|
||||
// Retrieve the duplicated states
|
||||
offset = 0;
|
||||
while (offset < numstates) {
|
||||
|
||||
statemap_ptr = &data->statemap[offset];
|
||||
int length = utarray_len(statemap_ptr->nums);
|
||||
if (length >= 2) {
|
||||
|
||||
data->recurIdx[data->recurlen] = statemap_ptr->nums;
|
||||
data->recurlen += 1;
|
||||
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
}
|
||||
|
||||
// data->getdupesret = get_dupes(data->orig_walk, &data->recurlen);
|
||||
|
||||
ck_free(automaton_fn);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
255
custom_mutators/gramatron/gramfuzz.h
Normal file
255
custom_mutators/gramatron/gramfuzz.h
Normal file
@ -0,0 +1,255 @@
|
||||
#ifndef _GRAMFUZZ_H
|
||||
|
||||
#define _GRAMFUZZ_H
|
||||
|
||||
#include <json-c/json.h>
|
||||
#include <unistd.h>
|
||||
#include "hashmap.h"
|
||||
#include "uthash.h"
|
||||
#include "utarray.h"
|
||||
|
||||
#define INIT_INPUTS 100 // No. of initial inputs to be generated
|
||||
|
||||
// Set this as `numstates` + 1 where `numstates` is retrieved from gen automata
|
||||
// json #define STATES 63
|
||||
|
||||
#define INIT_SIZE 100 // Initial size of the dynamic array holding the input
|
||||
|
||||
#define SPLICE_CORPUS 10000
|
||||
#define RECUR_THRESHOLD 6
|
||||
#define SIZE_THRESHOLD 2048
|
||||
|
||||
#define FLUSH_INTERVAL \
|
||||
3600 // Inputs that gave new coverage will be dumped every FLUSH_INTERVAL
|
||||
// seconds
|
||||
|
||||
afl_state_t *global_afl;
|
||||
|
||||
typedef struct trigger {
|
||||
|
||||
char * id;
|
||||
int dest;
|
||||
char * term;
|
||||
size_t term_len;
|
||||
|
||||
} trigger;
|
||||
|
||||
typedef struct state {
|
||||
|
||||
int state_name; // Integer State name
|
||||
int trigger_len; // Number of triggers associated with this state
|
||||
trigger *ptr; // Pointer to beginning of the list of triggers
|
||||
|
||||
} state;
|
||||
|
||||
typedef struct terminal {
|
||||
|
||||
int state;
|
||||
int trigger_idx;
|
||||
size_t symbol_len;
|
||||
char * symbol;
|
||||
|
||||
} terminal;
|
||||
|
||||
typedef struct buckethash {
|
||||
|
||||
int freq;
|
||||
|
||||
} buckethash;
|
||||
|
||||
int init_state;
|
||||
int curr_state;
|
||||
int final_state;
|
||||
int numstates;
|
||||
|
||||
/*****************
|
||||
/ DYNAMIC ARRAY FOR WALKS
|
||||
*****************/
|
||||
|
||||
typedef struct {
|
||||
|
||||
size_t used;
|
||||
size_t size;
|
||||
size_t inputlen;
|
||||
terminal *start;
|
||||
|
||||
} Array;
|
||||
|
||||
/*****************
|
||||
/ DYNAMIC ARRAY FOR STATEMAPS/RECURSION MAPS
|
||||
*****************/
|
||||
|
||||
typedef struct {
|
||||
|
||||
int * array;
|
||||
size_t used;
|
||||
size_t size;
|
||||
|
||||
} IdxMap;
|
||||
|
||||
typedef struct {
|
||||
|
||||
UT_array *nums;
|
||||
|
||||
} IdxMap_new;
|
||||
|
||||
typedef struct {
|
||||
|
||||
IdxMap_new *idxmap;
|
||||
UT_array ** recurIdx;
|
||||
|
||||
} Get_Dupes_Ret;
|
||||
|
||||
/* Candidate Struct */
|
||||
typedef struct {
|
||||
|
||||
Array * walk;
|
||||
IdxMap_new *statemap;
|
||||
|
||||
} Candidate;
|
||||
|
||||
/* Splice Mutation helpers*/
|
||||
typedef struct {
|
||||
|
||||
Candidate *splice_cand;
|
||||
int idx;
|
||||
|
||||
} SpliceCand;
|
||||
|
||||
typedef struct {
|
||||
|
||||
SpliceCand *start;
|
||||
size_t used;
|
||||
size_t size;
|
||||
|
||||
} SpliceCandArray;
|
||||
|
||||
// Initialize dynamic array for potential splice points
|
||||
SpliceCand potential[SPLICE_CORPUS];
|
||||
|
||||
typedef struct {
|
||||
|
||||
int orig_idx;
|
||||
int splice_idx;
|
||||
|
||||
} intpair_t;
|
||||
|
||||
// Initialize dynamic array for potential splice points
|
||||
// SpliceCand potential[SPLICE_CORPUS];
|
||||
// IdxMap_new* rcuridx[STATES];
|
||||
|
||||
/* Prototypes*/
|
||||
Array * slice(Array *, int);
|
||||
state * create_pda(u8 *);
|
||||
Array * gen_input(state *, Array *);
|
||||
Array * gen_input_count(state *, Array *, int *);
|
||||
int updatebucket(map_t, int);
|
||||
void itoa(int, char *, int);
|
||||
void strrreverse(char *, char *);
|
||||
void dbg_hashmap(map_t);
|
||||
void print_repr(Array *, char *);
|
||||
int isSatisfied(map_t);
|
||||
char * get_state(char *);
|
||||
Candidate *gen_candidate(Array *);
|
||||
|
||||
Array *spliceGF(Array *, Array *, int);
|
||||
Array *performSpliceOne(Array *, IdxMap_new *, Array *);
|
||||
/* Mutation Methods*/
|
||||
Array * performRandomMutation(state *, Array *);
|
||||
Array * performRandomMutationCount(state *, Array *, int *);
|
||||
Array * performSpliceMutationBench(state *, Array *, Candidate **);
|
||||
UT_array **get_dupes(Array *, int *);
|
||||
Array * doMult(Array *, UT_array **, int);
|
||||
Array * doMultBench(Array *, UT_array **, int);
|
||||
|
||||
/* Benchmarks*/
|
||||
void SpaceBenchmark(char *);
|
||||
void GenInputBenchmark(char *, char *);
|
||||
void RandomMutationBenchmark(char *, char *);
|
||||
void MutationAggrBenchmark(char *, char *);
|
||||
void SpliceMutationBenchmark(char *, char *);
|
||||
void SpliceMutationBenchmarkOne(char *, char *);
|
||||
void RandomRecursiveBenchmark(char *, char *);
|
||||
|
||||
/* Testers */
|
||||
void SanityCheck(char *);
|
||||
|
||||
/*Helpers*/
|
||||
void initArray(Array *, size_t);
|
||||
void insertArray(Array *, int, char *, size_t, int);
|
||||
void freeArray(Array *);
|
||||
void initArrayIdx(IdxMap *, size_t);
|
||||
void insertArrayIdx(IdxMap *, int);
|
||||
void freeArrayIdx(IdxMap *);
|
||||
void initArraySplice(SpliceCandArray *, size_t);
|
||||
void insertArraySplice(SpliceCandArray *, Candidate *, int);
|
||||
void freeArraySplice(IdxMap *);
|
||||
void getTwoIndices(UT_array *, int, int *, int *);
|
||||
void swap(int *, int *);
|
||||
Array *slice_inverse(Array *, int);
|
||||
void concatPrefixFeature(Array *, Array *);
|
||||
void concatPrefixFeatureBench(Array *, Array *);
|
||||
Array *carve(Array *, int, int);
|
||||
int fact(int);
|
||||
|
||||
void add_to_corpus(struct json_object *, Array *);
|
||||
struct json_object *term_to_json(terminal *);
|
||||
|
||||
/* Gramatron specific prototypes */
|
||||
u8 * unparse_walk(Array *);
|
||||
Array *performSpliceGF(state *, Array *, afl_state_t *);
|
||||
void dump_input(u8 *, char *, int *);
|
||||
void write_input(Array *, u8 *);
|
||||
Array *read_input(state *, u8 *);
|
||||
state *pda;
|
||||
|
||||
// // AFL-specific struct
|
||||
// typedef uint8_t u8;
|
||||
// typedef uint16_t u16;
|
||||
// typedef uint32_t u32;
|
||||
// #ifdef __x86_64__
|
||||
// typedef unsigned long long u64;
|
||||
// #else
|
||||
// typedef uint64_t u64;
|
||||
// #endif /* ^__x86_64__ */
|
||||
//
|
||||
// struct queue_entry {
|
||||
|
||||
// Array* walk; /* Pointer to the automaton walk*/
|
||||
// u32 walk_len; /* Number of tokens in the input*/
|
||||
// Candidate* cand; /* Preprocessed info about the
|
||||
// candidate to allow for faster mutations*/
|
||||
//
|
||||
// u8* fname; /* File name for the test case */
|
||||
// u32 len; /* Input length */
|
||||
// UT_array** recur_idx; /* Keeps track of recursive feature
|
||||
// indices*/
|
||||
//
|
||||
// u32 recur_len; /* The number of recursive features*/
|
||||
//
|
||||
// u8 cal_failed, /* Calibration failed? */
|
||||
// trim_done, /* Trimmed? */
|
||||
// was_fuzzed, /* Had any fuzzing done yet? */
|
||||
// passed_det, /* Deterministic stages passed? */
|
||||
// has_new_cov, /* Triggers new coverage? */
|
||||
// var_behavior, /* Variable behavior? */
|
||||
// favored, /* Currently favored? */
|
||||
// fs_redundant; /* Marked as redundant in the fs? */
|
||||
//
|
||||
// u32 bitmap_size, /* Number of bits set in bitmap */
|
||||
// exec_cksum; /* Checksum of the execution trace */
|
||||
//
|
||||
// u64 exec_us, /* Execution time (us) */
|
||||
// handicap, /* Number of queue cycles behind */
|
||||
// depth; /* Path depth */
|
||||
//
|
||||
// u8* trace_mini; /* Trace bytes, if kept */
|
||||
// u32 tc_ref; /* Trace bytes ref count */
|
||||
//
|
||||
// struct queue_entry *next, /* Next element, if any */
|
||||
// *next_100; /* 100 elements ahead */
|
||||
//
|
||||
// };
|
||||
|
||||
#endif
|
||||
|
606
custom_mutators/gramatron/grammars/js/source.json
Normal file
606
custom_mutators/gramatron/grammars/js/source.json
Normal file
@ -0,0 +1,606 @@
|
||||
{
|
||||
"ARGLIST": [
|
||||
"EXPR ',' ARGLIST",
|
||||
"EXPR",
|
||||
"EXPR ',' ARGLIST",
|
||||
"EXPR"
|
||||
],
|
||||
"ARGS": [
|
||||
"'()'",
|
||||
"'(' ARGLIST ')'",
|
||||
"'()'",
|
||||
"'(' ARGLIST ')'"
|
||||
],
|
||||
"ARITHMETICOPERATION": [
|
||||
"EXPR '/' EXPR",
|
||||
"EXPR '*' EXPR",
|
||||
"EXPR '+' EXPR",
|
||||
"EXPR '-' EXPR",
|
||||
"EXPR '%' EXPR",
|
||||
"EXPR '**' EXPR",
|
||||
"EXPR '++'"
|
||||
],
|
||||
"ARRAY": [
|
||||
"'[' ARRAYCONTENT ']'",
|
||||
"'[]'"
|
||||
],
|
||||
"ARRAYCONTENT": [
|
||||
"EXPR ',' ARRAYCONTENT",
|
||||
"EXPR"
|
||||
],
|
||||
"BOOLEAN": [
|
||||
"'true'",
|
||||
"'false'"
|
||||
],
|
||||
"BYTEWISEOPERATION": [
|
||||
"EXPR '&' EXPR",
|
||||
"EXPR '|' EXPR"
|
||||
],
|
||||
"COMPARISONOPERATION": [
|
||||
"EXPR '<' EXPR"
|
||||
],
|
||||
"DECIMALDIGITS": [
|
||||
"'20'",
|
||||
"'1234'",
|
||||
"'66'",
|
||||
"'234_9'",
|
||||
"'99999999999999999999'"
|
||||
],
|
||||
"DECIMALNUMBER": [
|
||||
"DECIMALDIGITS"
|
||||
],
|
||||
"EXPR": [
|
||||
"'(' EXPR ')'",
|
||||
"VAR",
|
||||
"'delete' SP EXPR",
|
||||
"'new' SP IDENTIFIER ARGS",
|
||||
"LITERAL",
|
||||
"IDENTIFIER",
|
||||
"METHODCALL",
|
||||
"'(' ARITHMETICOPERATION ')'",
|
||||
"'(' COMPARISONOPERATION ')'",
|
||||
"'(' BYTEWISEOPERATION ')'",
|
||||
"'(' LOGICALOPERATION ')'"
|
||||
],
|
||||
"IDENTIFIER": [
|
||||
"'Object'",
|
||||
"VAR",
|
||||
"'Function'",
|
||||
"'main'",
|
||||
"'opt'",
|
||||
"'Boolean'",
|
||||
"'Symbol'",
|
||||
"'JSON'",
|
||||
"'Error'",
|
||||
"'EvalError'",
|
||||
"'RangeError'",
|
||||
"'ReferenceError'",
|
||||
"'SyntaxError'",
|
||||
"'TypeError'",
|
||||
"'URIError'",
|
||||
"'this'",
|
||||
"'Number'",
|
||||
"'Math'",
|
||||
"'Date'",
|
||||
"'String'",
|
||||
"'RegExp'",
|
||||
"'Array'",
|
||||
"'Int8Array'",
|
||||
"'Uint8Array'",
|
||||
"'Uint8ClampedArray'",
|
||||
"'Int16Array'",
|
||||
"'Uint16Array'",
|
||||
"'Int32Array'",
|
||||
"'Uint32Array'",
|
||||
"'Float32Array'",
|
||||
"'Float64Array'",
|
||||
"'DataView'",
|
||||
"'ArrayBuffer'",
|
||||
"'Map'",
|
||||
"'Set'",
|
||||
"'WeakMap'",
|
||||
"'WeakSet'",
|
||||
"'Promise'",
|
||||
"'AsyncFunction'",
|
||||
"'asyncGenerator'",
|
||||
"'Reflect'",
|
||||
"'Proxy'",
|
||||
"'Intl'",
|
||||
"'Intl.Collator'",
|
||||
"'Intl.DateTimeFormat'",
|
||||
"'Intl.NumberFormat'",
|
||||
"'Intl.PluralRules'",
|
||||
"'WebAssembly'",
|
||||
"'WebAssembly.Module'",
|
||||
"'WebAssembly.Instance'",
|
||||
"'WebAssembly.Memory'",
|
||||
"'WebAssembly.Table'",
|
||||
"'WebAssembly.CompileError'",
|
||||
"'WebAssembly.LinkError'",
|
||||
"'WebAssembly.RuntimeError'",
|
||||
"'arguments'",
|
||||
"'Infinity'",
|
||||
"'NaN'",
|
||||
"'undefined'",
|
||||
"'null'",
|
||||
"'console'",
|
||||
"' '"
|
||||
],
|
||||
"IDENTIFIERLIST": [
|
||||
"IDENTIFIER ',' IDENTIFIERLIST",
|
||||
"'(' IDENTIFIERLIST '),' IDENTIFIERLIST",
|
||||
"IDENTIFIER"
|
||||
],
|
||||
"JSBLOCK": [
|
||||
"JSSTATEMENT",
|
||||
"JSSTATEMENT JSBLOCK"
|
||||
],
|
||||
"JSSTATEMENT": [
|
||||
"STATEMENT NEWLINE"
|
||||
],
|
||||
"LITERAL": [
|
||||
"'null'",
|
||||
"BOOLEAN",
|
||||
"NUMBER",
|
||||
"ARRAY"
|
||||
],
|
||||
"LOGICALOPERATION": [
|
||||
"EXPR '&&' EXPR",
|
||||
"EXPR '||' EXPR"
|
||||
],
|
||||
"METHODCALL": [
|
||||
"OBJECT PROPERTY METHODCALL1"
|
||||
],
|
||||
"METHODCALL1": [
|
||||
"'.' METHOD_NAME ARGS METHODCALL1",
|
||||
"' '"
|
||||
],
|
||||
"METHOD_NAME": [
|
||||
"IDENTIFIER",
|
||||
"'print'",
|
||||
"'eval'",
|
||||
"'uneval'",
|
||||
"'isFinite'",
|
||||
"'isNaN'",
|
||||
"'parseFloat'",
|
||||
"'parseInt'",
|
||||
"'decodeURI'",
|
||||
"'decodeURIComponent'",
|
||||
"'encodeURI'",
|
||||
"'encodeURIComponent'",
|
||||
"'escape'",
|
||||
"'unescape'",
|
||||
"'assign'",
|
||||
"'create'",
|
||||
"'defineProperty'",
|
||||
"'defineProperties'",
|
||||
"'entries'",
|
||||
"'freeze'",
|
||||
"'getOwnPropertyDescriptor'",
|
||||
"'getOwnPropertyDescriptors'",
|
||||
"'getOwnPropertyNames'",
|
||||
"'getOwnPropertySymbols'",
|
||||
"'getPrototypeOf'",
|
||||
"'is'",
|
||||
"'isExtensible'",
|
||||
"'isFrozen'",
|
||||
"'isSealed'",
|
||||
"'keys'",
|
||||
"'preventExtensions'",
|
||||
"'seal'",
|
||||
"'setPrototypeOf'",
|
||||
"'values'",
|
||||
"'__defineGetter__'",
|
||||
"'__defineSetter__'",
|
||||
"'__lookupGetter__'",
|
||||
"'__lookupSetter__'",
|
||||
"'hasOwnProperty'",
|
||||
"'isPrototypeOf'",
|
||||
"'propertyIsEnumerable'",
|
||||
"'toSource'",
|
||||
"'toLocaleString'",
|
||||
"'toString'",
|
||||
"'unwatch'",
|
||||
"'valueOf'",
|
||||
"'watch'",
|
||||
"'apply'",
|
||||
"'bind'",
|
||||
"'call'",
|
||||
"'isGenerator'",
|
||||
"'valueOf'",
|
||||
"'for'",
|
||||
"'keyFor'",
|
||||
"'stringify'",
|
||||
"'isInteger'",
|
||||
"'isSafeInteger'",
|
||||
"'toInteger'",
|
||||
"'toExponential'",
|
||||
"'toFixed'",
|
||||
"'toLocaleString'",
|
||||
"'toPrecision'",
|
||||
"'abs'",
|
||||
"'acos'",
|
||||
"'acosh'",
|
||||
"'asin'",
|
||||
"'asinh'",
|
||||
"'atan'",
|
||||
"'atanh'",
|
||||
"'atan2'",
|
||||
"'cbrt'",
|
||||
"'ceil'",
|
||||
"'clz32'",
|
||||
"'cos'",
|
||||
"'cosh'",
|
||||
"'exp'",
|
||||
"'expm1'",
|
||||
"'floor'",
|
||||
"'fround'",
|
||||
"'hypot'",
|
||||
"'imul'",
|
||||
"'log'",
|
||||
"'log1p'",
|
||||
"'log10'",
|
||||
"'log2'",
|
||||
"'max'",
|
||||
"'min'",
|
||||
"'pow'",
|
||||
"'random'",
|
||||
"'round'",
|
||||
"'sign'",
|
||||
"'sin'",
|
||||
"'sinh'",
|
||||
"'sqrt'",
|
||||
"'tan'",
|
||||
"'tanh'",
|
||||
"'trunc'",
|
||||
"'now'",
|
||||
"'parse'",
|
||||
"'UTC'",
|
||||
"'getDate'",
|
||||
"'getDay'",
|
||||
"'getFullYear'",
|
||||
"'getHours'",
|
||||
"'getMilliseconds'",
|
||||
"'getMinutes'",
|
||||
"'getMonth'",
|
||||
"'getSeconds'",
|
||||
"'getTime'",
|
||||
"'getTimezoneOffset'",
|
||||
"'getUTCDate'",
|
||||
"'getUTCDay'",
|
||||
"'getUTCFullYear'",
|
||||
"'getUTCHours'",
|
||||
"'getUTCMilliseconds'",
|
||||
"'getUTCMinutes'",
|
||||
"'getUTCMonth'",
|
||||
"'getUTCSeconds'",
|
||||
"'getYear'",
|
||||
"'setDate'",
|
||||
"'setFullYear'",
|
||||
"'setHours'",
|
||||
"'setMilliseconds'",
|
||||
"'setMinutes'",
|
||||
"'setMonth'",
|
||||
"'setSeconds'",
|
||||
"'setTime'",
|
||||
"'setUTCDate'",
|
||||
"'setUTCFullYear'",
|
||||
"'setUTCHours'",
|
||||
"'setUTCMilliseconds'",
|
||||
"'setUTCMinutes'",
|
||||
"'setUTCMonth'",
|
||||
"'setUTCSeconds'",
|
||||
"'setYear'",
|
||||
"'toDateString'",
|
||||
"'toISOString'",
|
||||
"'toJSON'",
|
||||
"'toGMTString'",
|
||||
"'toLocaleDateString'",
|
||||
"'toLocaleFormat'",
|
||||
"'toLocaleString'",
|
||||
"'toLocaleTimeString'",
|
||||
"'toTimeString'",
|
||||
"'toUTCString'",
|
||||
"'indexOf'",
|
||||
"'substring'",
|
||||
"'charAt'",
|
||||
"'strcmp'",
|
||||
"'fromCharCode'",
|
||||
"'fromCodePoint'",
|
||||
"'raw'",
|
||||
"'charCodeAt'",
|
||||
"'slice'",
|
||||
"'codePointAt'",
|
||||
"'concat'",
|
||||
"'includes'",
|
||||
"'endsWith'",
|
||||
"'lastIndexOf'",
|
||||
"'localeCompare'",
|
||||
"'match'",
|
||||
"'normalize'",
|
||||
"'padEnd'",
|
||||
"'padStart'",
|
||||
"'quote'",
|
||||
"'repeat'",
|
||||
"'replace'",
|
||||
"'search'",
|
||||
"'split'",
|
||||
"'startsWith'",
|
||||
"'substr'",
|
||||
"'toLocaleLowerCase'",
|
||||
"'toLocaleUpperCase'",
|
||||
"'toLowerCase'",
|
||||
"'toUpperCase'",
|
||||
"'trim'",
|
||||
"'trimleft'",
|
||||
"'trimright'",
|
||||
"'anchor'",
|
||||
"'big'",
|
||||
"'blink'",
|
||||
"'bold'",
|
||||
"'fixed'",
|
||||
"'fontcolor'",
|
||||
"'fontsize'",
|
||||
"'italics'",
|
||||
"'link'",
|
||||
"'small'",
|
||||
"'strike'",
|
||||
"'sub'",
|
||||
"'sup'",
|
||||
"'compile'",
|
||||
"'exec'",
|
||||
"'test'",
|
||||
"'from'",
|
||||
"'isArray'",
|
||||
"'of'",
|
||||
"'copyWithin'",
|
||||
"'fill'",
|
||||
"'pop'",
|
||||
"'push'",
|
||||
"'reverse'",
|
||||
"'shift'",
|
||||
"'sort'",
|
||||
"'splice'",
|
||||
"'unshift'",
|
||||
"'concat'",
|
||||
"'join'",
|
||||
"'every'",
|
||||
"'filter'",
|
||||
"'findIndex'",
|
||||
"'forEach'",
|
||||
"'map'",
|
||||
"'reduce'",
|
||||
"'reduceRight'",
|
||||
"'some'",
|
||||
"'move'",
|
||||
"'getInt8'",
|
||||
"'getUint8'",
|
||||
"'getInt16'",
|
||||
"'getUint16'",
|
||||
"'getInt32'",
|
||||
"'getUint32'",
|
||||
"'getFloat32'",
|
||||
"'getFloat64'",
|
||||
"'setInt8'",
|
||||
"'setUint8'",
|
||||
"'setInt16'",
|
||||
"'setUint16'",
|
||||
"'setInt32'",
|
||||
"'setUint32'",
|
||||
"'setFloat32'",
|
||||
"'setFloat64'",
|
||||
"'isView'",
|
||||
"'transfer'",
|
||||
"'clear'",
|
||||
"'get'",
|
||||
"'has'",
|
||||
"'set'",
|
||||
"'add'",
|
||||
"'splat'",
|
||||
"'check'",
|
||||
"'extractLane'",
|
||||
"'replaceLane'",
|
||||
"'load'",
|
||||
"'load1'",
|
||||
"'load2'",
|
||||
"'load3'",
|
||||
"'store'",
|
||||
"'store1'",
|
||||
"'store2'",
|
||||
"'store3'",
|
||||
"'addSaturate'",
|
||||
"'div'",
|
||||
"'mul'",
|
||||
"'neg'",
|
||||
"'reciprocalApproximation'",
|
||||
"'reciprocalSqrtApproximation'",
|
||||
"'subSaturate'",
|
||||
"'shuffle'",
|
||||
"'swizzle'",
|
||||
"'maxNum'",
|
||||
"'minNum'",
|
||||
"'select'",
|
||||
"'equal'",
|
||||
"'notEqual'",
|
||||
"'lessThan'",
|
||||
"'lessThanOrEqual'",
|
||||
"'greaterThan'",
|
||||
"'greaterThanOrEqual'",
|
||||
"'and'",
|
||||
"'or'",
|
||||
"'xor'",
|
||||
"'not'",
|
||||
"'shiftLeftByScalar'",
|
||||
"'shiftRightByScalar'",
|
||||
"'allTrue'",
|
||||
"'anyTrue'",
|
||||
"'fromFloat32x4'",
|
||||
"'fromFloat32x4Bits'",
|
||||
"'fromFloat64x2Bits'",
|
||||
"'fromInt32x4'",
|
||||
"'fromInt32x4Bits'",
|
||||
"'fromInt16x8Bits'",
|
||||
"'fromInt8x16Bits'",
|
||||
"'fromUint32x4'",
|
||||
"'fromUint32x4Bits'",
|
||||
"'fromUint16x8Bits'",
|
||||
"'fromUint8x16Bits'",
|
||||
"'neg'",
|
||||
"'compareExchange'",
|
||||
"'exchange'",
|
||||
"'wait'",
|
||||
"'wake'",
|
||||
"'isLockFree'",
|
||||
"'all'",
|
||||
"'race'",
|
||||
"'reject'",
|
||||
"'resolve'",
|
||||
"'catch'",
|
||||
"'then'",
|
||||
"'finally'",
|
||||
"'next'",
|
||||
"'throw'",
|
||||
"'close'",
|
||||
"'send'",
|
||||
"'apply'",
|
||||
"'construct'",
|
||||
"'deleteProperty'",
|
||||
"'ownKeys'",
|
||||
"'getCanonicalLocales'",
|
||||
"'supportedLocalesOf'",
|
||||
"'resolvedOptions'",
|
||||
"'formatToParts'",
|
||||
"'resolvedOptions'",
|
||||
"'instantiate'",
|
||||
"'instantiateStreaming'",
|
||||
"'compileStreaming'",
|
||||
"'validate'",
|
||||
"'customSections'",
|
||||
"'exports'",
|
||||
"'imports'",
|
||||
"'grow'",
|
||||
"'super'",
|
||||
"'in'",
|
||||
"'instanceof'",
|
||||
"' '"
|
||||
],
|
||||
"NEWLINE": [
|
||||
"'\\n'"
|
||||
],
|
||||
"NUMBER": [
|
||||
"'1/2'",
|
||||
"'1E2'",
|
||||
"'1E02'",
|
||||
"'1E+02'",
|
||||
"'-1'",
|
||||
"'-1.00'",
|
||||
"'-1/2'",
|
||||
"'-1E2'",
|
||||
"'-1E02'",
|
||||
"'-1E+02'",
|
||||
"'1/0'",
|
||||
"'0/0'",
|
||||
"'-2147483648/-1'",
|
||||
"'-9223372036854775808/-1'",
|
||||
"'-0'",
|
||||
"'-0.0'",
|
||||
"'+0'"
|
||||
],
|
||||
"OBJECT": [
|
||||
"IDENTIFIER"
|
||||
],
|
||||
"PROGRAM": [
|
||||
"JSBLOCK"
|
||||
],
|
||||
"PROPERTY": [
|
||||
"'.length' PROPERTY",
|
||||
"'.prototype' PROPERTY",
|
||||
"'.constructor' PROPERTY",
|
||||
"'.__proto__' PROPERTY",
|
||||
"'.__noSuchMethod__' PROPERTY",
|
||||
"'.__count__' PROPERTY",
|
||||
"'.__parent__' PROPERTY",
|
||||
"'.arguments' PROPERTY",
|
||||
"'.arity' PROPERTY",
|
||||
"'.caller' PROPERTY",
|
||||
"'.name' PROPERTY",
|
||||
"'.displayName' PROPERTY",
|
||||
"'.iterator' PROPERTY",
|
||||
"'.asyncIterator' PROPERTY",
|
||||
"'.match' PROPERTY",
|
||||
"'.replace' PROPERTY",
|
||||
"'.search' PROPERTY",
|
||||
"'.split' PROPERTY",
|
||||
"'.hasInstance' PROPERTY",
|
||||
"'.isConcatSpreadable' PROPERTY",
|
||||
"'.unscopables' PROPERTY",
|
||||
"'.species' PROPERTY",
|
||||
"'.toPrimitive' PROPERTY",
|
||||
"'.toStringTag' PROPERTY",
|
||||
"'.fileName' PROPERTY",
|
||||
"'.lineNumber' PROPERTY",
|
||||
"'.columnNumber' PROPERTY",
|
||||
"'.message' PROPERTY",
|
||||
"'.name' PROPERTY",
|
||||
"'.EPSILON' PROPERTY",
|
||||
"'.MAX_SAFE_INTEGER' PROPERTY",
|
||||
"'.MAX_VALUE' PROPERTY",
|
||||
"'.MIN_SAFE_INTEGER' PROPERTY",
|
||||
"'.MIN_VALUE' PROPERTY",
|
||||
"'.NaN' PROPERTY",
|
||||
"'.NEGATIVE_INFINITY' PROPERTY",
|
||||
"'.POSITIVE_INFINITY' PROPERTY",
|
||||
"'.E' PROPERTY",
|
||||
"'.LN2' PROPERTY",
|
||||
"'.LN10' PROPERTY",
|
||||
"'.LOG2E' PROPERTY",
|
||||
"'.LOG10E' PROPERTY",
|
||||
"'.PI' PROPERTY",
|
||||
"'.SQRT1_2' PROPERTY",
|
||||
"'.SQRT2' PROPERTY",
|
||||
"'.flags' PROPERTY",
|
||||
"'.global' PROPERTY",
|
||||
"'.ignoreCase' PROPERTY",
|
||||
"'.multiline' PROPERTY",
|
||||
"'.source' PROPERTY",
|
||||
"'.sticky' PROPERTY",
|
||||
"'.unicode' PROPERTY",
|
||||
"'.buffer' PROPERTY",
|
||||
"'.byteLength' PROPERTY",
|
||||
"'.byteOffset' PROPERTY",
|
||||
"'.BYTES_PER_ELEMENT' PROPERTY",
|
||||
"'.compare' PROPERTY",
|
||||
"'.format' PROPERTY",
|
||||
"'.callee' PROPERTY",
|
||||
"'.caller' PROPERTY",
|
||||
"'.memory' PROPERTY",
|
||||
"'.exports' PROPERTY",
|
||||
"' '"
|
||||
],
|
||||
"SP": [
|
||||
"' '"
|
||||
],
|
||||
"STATEMENT": [
|
||||
"EXPR ';'",
|
||||
"'var' SP VAR '=' EXPR ';'",
|
||||
"'let' SP VAR '=' EXPR ';'",
|
||||
"VAR '=' EXPR ';'",
|
||||
"VAR PROPERTY '=' EXPR ';'",
|
||||
"VAR '[' DECIMALNUMBER ']' '=' EXPR ';'",
|
||||
"'const' SP VAR '=' EXPR ';'",
|
||||
"'typeof' SP EXPR ';'",
|
||||
"'void' SP EXPR ';'",
|
||||
"'return' SP EXPR ';'",
|
||||
"VAR ':'"
|
||||
],
|
||||
"VAR": [
|
||||
"'a'",
|
||||
"'b'",
|
||||
"'c'",
|
||||
"'d'",
|
||||
"'e'",
|
||||
"'f'",
|
||||
"'g'",
|
||||
"'h'"
|
||||
]
|
||||
}
|
File diff suppressed because one or more lines are too long
8707
custom_mutators/gramatron/grammars/php/source.json
Normal file
8707
custom_mutators/gramatron/grammars/php/source.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1195
custom_mutators/gramatron/grammars/ruby/source.json
Normal file
1195
custom_mutators/gramatron/grammars/ruby/source.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
434
custom_mutators/gramatron/hashmap.c
Normal file
434
custom_mutators/gramatron/hashmap.c
Normal file
@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Generic map implementation.
|
||||
*/
|
||||
#include "hashmap.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define INITIAL_SIZE (256)
|
||||
#define MAX_CHAIN_LENGTH (8)
|
||||
|
||||
/* We need to keep keys and values */
|
||||
typedef struct _hashmap_element {
|
||||
|
||||
char *key;
|
||||
int in_use;
|
||||
any_t data;
|
||||
|
||||
} hashmap_element;
|
||||
|
||||
/* A hashmap has some maximum size and current size,
|
||||
* as well as the data to hold. */
|
||||
typedef struct _hashmap_map {
|
||||
|
||||
int table_size;
|
||||
int size;
|
||||
hashmap_element *data;
|
||||
|
||||
} hashmap_map;
|
||||
|
||||
/*
|
||||
* Return an empty hashmap, or NULL on failure.
|
||||
*/
|
||||
map_t hashmap_new() {
|
||||
|
||||
hashmap_map *m = (hashmap_map *)malloc(sizeof(hashmap_map));
|
||||
if (!m) goto err;
|
||||
|
||||
m->data = (hashmap_element *)calloc(INITIAL_SIZE, sizeof(hashmap_element));
|
||||
if (!m->data) goto err;
|
||||
|
||||
m->table_size = INITIAL_SIZE;
|
||||
m->size = 0;
|
||||
|
||||
return m;
|
||||
err:
|
||||
if (m) hashmap_free(m);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* The implementation here was originally done by Gary S. Brown. I have
|
||||
borrowed the tables directly, and made some minor changes to the
|
||||
crc32-function (including changing the interface). //ylo */
|
||||
|
||||
/* ============================================================= */
|
||||
/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
|
||||
/* code or tables extracted from it, as desired without restriction. */
|
||||
/* */
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
/* */
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
/* */
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* tions for all combinations of data and CRC register values. */
|
||||
/* */
|
||||
/* The values must be right-shifted by eight bits by the "updcrc" */
|
||||
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
/* polynomial $edb88320 */
|
||||
/* */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static unsigned long crc32_tab[] = {
|
||||
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL};
|
||||
|
||||
/* Return a 32-bit CRC of the contents of the buffer. */
|
||||
|
||||
unsigned long crc32(const unsigned char *s, unsigned int len) {
|
||||
|
||||
unsigned int i;
|
||||
unsigned long crc32val;
|
||||
|
||||
crc32val = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
|
||||
|
||||
}
|
||||
|
||||
return crc32val;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashing function for a string
|
||||
*/
|
||||
unsigned int hashmap_hash_int(hashmap_map *m, char *keystring) {
|
||||
|
||||
unsigned long key = crc32((unsigned char *)(keystring), strlen(keystring));
|
||||
|
||||
/* Robert Jenkins' 32 bit Mix Function */
|
||||
key += (key << 12);
|
||||
key ^= (key >> 22);
|
||||
key += (key << 4);
|
||||
key ^= (key >> 9);
|
||||
key += (key << 10);
|
||||
key ^= (key >> 2);
|
||||
key += (key << 7);
|
||||
key ^= (key >> 12);
|
||||
|
||||
/* Knuth's Multiplicative Method */
|
||||
key = (key >> 3) * 2654435761;
|
||||
|
||||
return key % m->table_size;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the integer of the location in data
|
||||
* to store the point to the item, or MAP_FULL.
|
||||
*/
|
||||
int hashmap_hash(map_t in, char *key) {
|
||||
|
||||
int curr;
|
||||
int i;
|
||||
|
||||
/* Cast the hashmap */
|
||||
hashmap_map *m = (hashmap_map *)in;
|
||||
|
||||
/* If full, return immediately */
|
||||
if (m->size >= (m->table_size / 2)) return MAP_FULL;
|
||||
|
||||
/* Find the best index */
|
||||
curr = hashmap_hash_int(m, key);
|
||||
|
||||
/* Linear probing */
|
||||
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
|
||||
|
||||
if (m->data[curr].in_use == 0) return curr;
|
||||
|
||||
if (m->data[curr].in_use == 1 && (strcmp(m->data[curr].key, key) == 0))
|
||||
return curr;
|
||||
|
||||
curr = (curr + 1) % m->table_size;
|
||||
|
||||
}
|
||||
|
||||
return MAP_FULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Doubles the size of the hashmap, and rehashes all the elements
|
||||
*/
|
||||
int hashmap_rehash(map_t in) {
|
||||
|
||||
int i;
|
||||
int old_size;
|
||||
hashmap_element *curr;
|
||||
|
||||
/* Setup the new elements */
|
||||
hashmap_map * m = (hashmap_map *)in;
|
||||
hashmap_element *temp =
|
||||
(hashmap_element *)calloc(2 * m->table_size, sizeof(hashmap_element));
|
||||
if (!temp) return MAP_OMEM;
|
||||
|
||||
/* Update the array */
|
||||
curr = m->data;
|
||||
m->data = temp;
|
||||
|
||||
/* Update the size */
|
||||
old_size = m->table_size;
|
||||
m->table_size = 2 * m->table_size;
|
||||
m->size = 0;
|
||||
|
||||
/* Rehash the elements */
|
||||
for (i = 0; i < old_size; i++) {
|
||||
|
||||
int status;
|
||||
|
||||
if (curr[i].in_use == 0) continue;
|
||||
|
||||
status = hashmap_put(m, curr[i].key, curr[i].data);
|
||||
if (status != MAP_OK) return status;
|
||||
|
||||
}
|
||||
|
||||
free(curr);
|
||||
|
||||
return MAP_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a pointer to the hashmap with some key
|
||||
*/
|
||||
int hashmap_put(map_t in, char *key, any_t value) {
|
||||
|
||||
int index;
|
||||
hashmap_map *m;
|
||||
|
||||
/* Cast the hashmap */
|
||||
m = (hashmap_map *)in;
|
||||
|
||||
/* Find a place to put our value */
|
||||
index = hashmap_hash(in, key);
|
||||
while (index == MAP_FULL) {
|
||||
|
||||
if (hashmap_rehash(in) == MAP_OMEM) { return MAP_OMEM; }
|
||||
index = hashmap_hash(in, key);
|
||||
|
||||
}
|
||||
|
||||
/* Set the data */
|
||||
m->data[index].data = value;
|
||||
m->data[index].key = key;
|
||||
m->data[index].in_use = 1;
|
||||
m->size++;
|
||||
|
||||
return MAP_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Get your pointer out of the hashmap with a key
|
||||
*/
|
||||
int hashmap_get(map_t in, char *key, any_t *arg) {
|
||||
|
||||
int curr;
|
||||
int i;
|
||||
hashmap_map *m;
|
||||
|
||||
/* Cast the hashmap */
|
||||
m = (hashmap_map *)in;
|
||||
|
||||
/* Find data location */
|
||||
curr = hashmap_hash_int(m, key);
|
||||
|
||||
/* Linear probing, if necessary */
|
||||
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
|
||||
|
||||
int in_use = m->data[curr].in_use;
|
||||
if (in_use == 1) {
|
||||
|
||||
if (strcmp(m->data[curr].key, key) == 0) {
|
||||
|
||||
*arg = (m->data[curr].data);
|
||||
return MAP_OK;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
curr = (curr + 1) % m->table_size;
|
||||
|
||||
}
|
||||
|
||||
*arg = NULL;
|
||||
|
||||
/* Not found */
|
||||
return MAP_MISSING;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate the function parameter over each element in the hashmap. The
|
||||
* additional any_t argument is passed to the function as its first
|
||||
* argument and the hashmap element is the second.
|
||||
*/
|
||||
int hashmap_iterate(map_t in, PFany f, any_t item) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Cast the hashmap */
|
||||
hashmap_map *m = (hashmap_map *)in;
|
||||
|
||||
/* On empty hashmap, return immediately */
|
||||
if (hashmap_length(m) <= 0) return MAP_MISSING;
|
||||
|
||||
/* Linear probing */
|
||||
for (i = 0; i < m->table_size; i++)
|
||||
if (m->data[i].in_use != 0) {
|
||||
|
||||
any_t data = (any_t)(m->data[i].data);
|
||||
int status = f(item, data);
|
||||
if (status != MAP_OK) { return status; }
|
||||
|
||||
}
|
||||
|
||||
return MAP_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an element with that key from the map
|
||||
*/
|
||||
int hashmap_remove(map_t in, char *key) {
|
||||
|
||||
int i;
|
||||
int curr;
|
||||
hashmap_map *m;
|
||||
|
||||
/* Cast the hashmap */
|
||||
m = (hashmap_map *)in;
|
||||
|
||||
/* Find key */
|
||||
curr = hashmap_hash_int(m, key);
|
||||
|
||||
/* Linear probing, if necessary */
|
||||
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
|
||||
|
||||
int in_use = m->data[curr].in_use;
|
||||
if (in_use == 1) {
|
||||
|
||||
if (strcmp(m->data[curr].key, key) == 0) {
|
||||
|
||||
/* Blank out the fields */
|
||||
m->data[curr].in_use = 0;
|
||||
m->data[curr].data = NULL;
|
||||
m->data[curr].key = NULL;
|
||||
|
||||
/* Reduce the size */
|
||||
m->size--;
|
||||
return MAP_OK;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
curr = (curr + 1) % m->table_size;
|
||||
|
||||
}
|
||||
|
||||
/* Data not found */
|
||||
return MAP_MISSING;
|
||||
|
||||
}
|
||||
|
||||
/* Deallocate the hashmap */
|
||||
void hashmap_free(map_t in) {
|
||||
|
||||
hashmap_map *m = (hashmap_map *)in;
|
||||
free(m->data);
|
||||
free(m);
|
||||
|
||||
}
|
||||
|
||||
/* Return the length of the hashmap */
|
||||
int hashmap_length(map_t in) {
|
||||
|
||||
hashmap_map *m = (hashmap_map *)in;
|
||||
if (m != NULL)
|
||||
return m->size;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
83
custom_mutators/gramatron/hashmap.h
Normal file
83
custom_mutators/gramatron/hashmap.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Generic hashmap manipulation functions
|
||||
*
|
||||
* Originally by Elliot C Back -
|
||||
* http://elliottback.com/wp/hashmap-implementation-in-c/
|
||||
*
|
||||
* Modified by Pete Warden to fix a serious performance problem, support strings
|
||||
* as keys and removed thread synchronization - http://petewarden.typepad.com
|
||||
*/
|
||||
#ifndef __HASHMAP_H__
|
||||
#define __HASHMAP_H__
|
||||
|
||||
#define MAP_MISSING -3 /* No such element */
|
||||
#define MAP_FULL -2 /* Hashmap is full */
|
||||
#define MAP_OMEM -1 /* Out of Memory */
|
||||
#define MAP_OK 0 /* OK */
|
||||
|
||||
/*
|
||||
* any_t is a pointer. This allows you to put arbitrary structures in
|
||||
* the hashmap.
|
||||
*/
|
||||
typedef void *any_t;
|
||||
|
||||
/*
|
||||
* PFany is a pointer to a function that can take two any_t arguments
|
||||
* and return an integer. Returns status code..
|
||||
*/
|
||||
typedef int (*PFany)(any_t, any_t);
|
||||
|
||||
/*
|
||||
* map_t is a pointer to an internally maintained data structure.
|
||||
* Clients of this package do not need to know how hashmaps are
|
||||
* represented. They see and manipulate only map_t's.
|
||||
*/
|
||||
typedef any_t map_t;
|
||||
|
||||
/*
|
||||
* Return an empty hashmap. Returns NULL if empty.
|
||||
*/
|
||||
extern map_t hashmap_new();
|
||||
|
||||
/*
|
||||
* Iteratively call f with argument (item, data) for
|
||||
* each element data in the hashmap. The function must
|
||||
* return a map status code. If it returns anything other
|
||||
* than MAP_OK the traversal is terminated. f must
|
||||
* not reenter any hashmap functions, or deadlock may arise.
|
||||
*/
|
||||
extern int hashmap_iterate(map_t in, PFany f, any_t item);
|
||||
|
||||
/*
|
||||
* Add an element to the hashmap. Return MAP_OK or MAP_OMEM.
|
||||
*/
|
||||
extern int hashmap_put(map_t in, char *key, any_t value);
|
||||
|
||||
/*
|
||||
* Get an element from the hashmap. Return MAP_OK or MAP_MISSING.
|
||||
*/
|
||||
extern int hashmap_get(map_t in, char *key, any_t *arg);
|
||||
|
||||
/*
|
||||
* Remove an element from the hashmap. Return MAP_OK or MAP_MISSING.
|
||||
*/
|
||||
extern int hashmap_remove(map_t in, char *key);
|
||||
|
||||
/*
|
||||
* Get any element. Return MAP_OK or MAP_MISSING.
|
||||
* remove - should the element be removed from the hashmap
|
||||
*/
|
||||
extern int hashmap_get_one(map_t in, any_t *arg, int remove);
|
||||
|
||||
/*
|
||||
* Free the hashmap
|
||||
*/
|
||||
extern void hashmap_free(map_t in);
|
||||
|
||||
/*
|
||||
* Get the current size of a hashmap
|
||||
*/
|
||||
extern int hashmap_length(map_t in);
|
||||
|
||||
#endif
|
||||
|
1
custom_mutators/gramatron/json-c
Submodule
1
custom_mutators/gramatron/json-c
Submodule
Submodule custom_mutators/gramatron/json-c added at af8dd4a307
275
custom_mutators/gramatron/preprocess/construct_automata.py
Normal file
275
custom_mutators/gramatron/preprocess/construct_automata.py
Normal file
@ -0,0 +1,275 @@
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
from collections import defaultdict
|
||||
# import pygraphviz as pgv
|
||||
|
||||
gram_data = None
|
||||
state_count = 1
|
||||
pda = []
|
||||
worklist = []
|
||||
state_stacks = {}
|
||||
|
||||
# === If user provides upper bound on the stack size during FSA creation ===
|
||||
# Specifies the upper bound to which the stack is allowed to grow
|
||||
# If for any generated state, the stack size is >= stack_limit then this
|
||||
# state is not expanded further.
|
||||
stack_limit = None
|
||||
# Holds the set of unexpanded rules owing to the user-passed stack constraint limit
|
||||
unexpanded_rules = set()
|
||||
|
||||
def main(grammar, limit):
|
||||
global worklist, gram_data, stack_limit
|
||||
current = '0'
|
||||
stack_limit = limit
|
||||
if stack_limit:
|
||||
print ('[X] Operating in bounded stack mode')
|
||||
|
||||
with open(grammar, 'r') as fd:
|
||||
gram_data = json.load(fd)
|
||||
start_symbol = gram_data["Start"][0]
|
||||
worklist.append([current, [start_symbol]])
|
||||
# print (grammar)
|
||||
filename = (grammar.split('/')[-1]).split('.')[0]
|
||||
|
||||
|
||||
while worklist:
|
||||
# Take an element from the worklist
|
||||
# print ('================')
|
||||
# print ('Worklist:', worklist)
|
||||
element = worklist.pop(0)
|
||||
prep_transitions(element)
|
||||
|
||||
pda_file = filename + '_transition.json'
|
||||
graph_file = filename + '.png'
|
||||
# print ('XXXXXXXXXXXXXXXX')
|
||||
# print ('PDA file:%s Png graph file:%s' % (pda_file, graph_file))
|
||||
# XXX Commented out because visualization of current version of PHP causes segfault
|
||||
# Create the graph and dump the transitions to a file
|
||||
# create_graph(filename)
|
||||
transformed = postprocess()
|
||||
with open(filename + '_automata.json', 'w+') as fd:
|
||||
json.dump(transformed, fd)
|
||||
with open(filename + '_transition.json', 'w+') as fd:
|
||||
json.dump(pda, fd)
|
||||
if not unexpanded_rules:
|
||||
print ('[X] No unexpanded rules, absolute FSA formed')
|
||||
exit(0)
|
||||
else:
|
||||
print ('[X] Certain rules were not expanded due to stack size limit. Inexact approximation has been created and the disallowed rules have been put in {}_disallowed.json'.format(filename))
|
||||
print ('[X] Number of unexpanded rules:', len(unexpanded_rules))
|
||||
with open(filename + '_disallowed.json', 'w+') as fd:
|
||||
json.dump(list(unexpanded_rules), fd)
|
||||
|
||||
def create_graph(filename):
|
||||
'''
|
||||
Creates a DOT representation of the PDA
|
||||
'''
|
||||
global pda
|
||||
G = pgv.AGraph(strict = False, directed = True)
|
||||
for transition in pda:
|
||||
print ('Transition:', transition)
|
||||
G.add_edge(transition['source'], transition['dest'],
|
||||
label = 'Term:{}'.format(transition['terminal']))
|
||||
G.layout(prog = 'dot')
|
||||
print ('Do it up 2')
|
||||
G.draw(filename + '.png')
|
||||
|
||||
def prep_transitions(element):
|
||||
'''
|
||||
Generates transitions
|
||||
'''
|
||||
global gram_data, state_count, pda, worklist, state_stacks, stack_limit, unexpanded_rules
|
||||
state = element[0]
|
||||
try:
|
||||
nonterminal = element[1][0]
|
||||
except IndexError:
|
||||
# Final state was encountered, pop from worklist without doing anything
|
||||
return
|
||||
rules = gram_data[nonterminal]
|
||||
count = 1
|
||||
for rule in rules:
|
||||
isRecursive = False
|
||||
# print ('Current state:', state)
|
||||
terminal, ss, termIsRegex = tokenize(rule)
|
||||
transition = get_template()
|
||||
transition['trigger'] = '_'.join([state, str(count)])
|
||||
transition['source'] = state
|
||||
transition['dest'] = str(state_count)
|
||||
transition['ss'] = ss
|
||||
transition['terminal'] = terminal
|
||||
transition['rule'] = "{} -> {}".format(nonterminal, rule )
|
||||
if termIsRegex:
|
||||
transition['termIsRegex'] = True
|
||||
|
||||
# Creating a state stack for the new state
|
||||
try:
|
||||
state_stack = state_stacks[state][:]
|
||||
except:
|
||||
state_stack = []
|
||||
if len(state_stack):
|
||||
state_stack.pop(0)
|
||||
if ss:
|
||||
for symbol in ss[::-1]:
|
||||
state_stack.insert(0, symbol)
|
||||
transition['stack'] = state_stack
|
||||
|
||||
# Check if a recursive transition state being created, if so make a backward
|
||||
# edge and don't add anything to the worklist
|
||||
# print (state_stacks)
|
||||
if state_stacks:
|
||||
for state_element, stack in state_stacks.items():
|
||||
# print ('Stack:', sorted(stack))
|
||||
# print ('State stack:', sorted(state_stack))
|
||||
if sorted(stack) == sorted(state_stack):
|
||||
transition['dest'] = state_element
|
||||
# print ('Recursive:', transition)
|
||||
pda.append(transition)
|
||||
count += 1
|
||||
isRecursive = True
|
||||
break
|
||||
# If a recursive transition exercised don't add the same transition as a new
|
||||
# edge, continue onto the next transitions
|
||||
if isRecursive:
|
||||
continue
|
||||
|
||||
# If the generated state has a stack size > stack_limit then that state is abandoned
|
||||
# and not added to the FSA or the worklist for further expansion
|
||||
if stack_limit:
|
||||
if (len(transition['stack']) > stack_limit):
|
||||
unexpanded_rules.add(transition['rule'])
|
||||
continue
|
||||
|
||||
# Create transitions for the non-recursive relations and add to the worklist
|
||||
# print ('Normal:', transition)
|
||||
# print ('State2:', state)
|
||||
pda.append(transition)
|
||||
worklist.append([transition['dest'], transition['stack']])
|
||||
state_stacks[transition['dest']] = state_stack
|
||||
state_count += 1
|
||||
count += 1
|
||||
|
||||
def tokenize(rule):
|
||||
'''
|
||||
Gets the terminal and the corresponding stack symbols from a rule in GNF form
|
||||
'''
|
||||
pattern = re.compile("([r])*\'([\s\S]+)\'([\s\S]*)")
|
||||
terminal = None
|
||||
ss = None
|
||||
termIsRegex = False
|
||||
match = pattern.match(rule)
|
||||
if match.group(1):
|
||||
termIsRegex = True
|
||||
if match.group(2):
|
||||
terminal = match.group(2)
|
||||
else:
|
||||
raise AssertionError("Rule is not in GNF form")
|
||||
|
||||
if match.group(3):
|
||||
ss = (match.group(3)).split()
|
||||
|
||||
return terminal, ss, termIsRegex
|
||||
|
||||
def get_template():
|
||||
transition_template = {
|
||||
'trigger':None,
|
||||
'source': None,
|
||||
'dest': None,
|
||||
'termIsRegex': False,
|
||||
'terminal' : None,
|
||||
'stack': []
|
||||
}
|
||||
return transition_template
|
||||
|
||||
def postprocess():
|
||||
'''
|
||||
Creates a representation to be passed on to the C-module
|
||||
'''
|
||||
global pda
|
||||
final_struct = {}
|
||||
memoized = defaultdict(list)
|
||||
# Supporting data structures for if stack limit is imposed
|
||||
culled_pda = []
|
||||
culled_final = []
|
||||
num_transitions = 0 # Keep track of number of transitions
|
||||
|
||||
|
||||
states, final, initial = _get_states()
|
||||
|
||||
print (initial)
|
||||
assert len(initial) == 1, 'More than one init state found'
|
||||
|
||||
# Cull transitions to states which were not expanded owing to the stack limit
|
||||
if stack_limit:
|
||||
|
||||
blocklist = []
|
||||
for final_state in final:
|
||||
for transition in pda:
|
||||
if (transition["dest"] == final_state) and (len(transition["stack"]) > 0):
|
||||
blocklist.append(transition["dest"])
|
||||
continue
|
||||
else:
|
||||
culled_pda.append(transition)
|
||||
|
||||
culled_final = [state for state in final if state not in blocklist]
|
||||
|
||||
assert len(culled_final) == 1, 'More than one final state found'
|
||||
|
||||
for transition in culled_pda:
|
||||
state = transition["source"]
|
||||
if transition["dest"] in blocklist:
|
||||
continue
|
||||
num_transitions += 1
|
||||
memoized[state].append([transition["trigger"], transition["dest"],
|
||||
transition["terminal"]])
|
||||
final_struct["init_state"] = initial
|
||||
final_struct["final_state"] = culled_final[0]
|
||||
# The reason we do this is because when states are culled, the indexing is
|
||||
# still relative to the actual number of states hence we keep numstates recorded
|
||||
# as the original number of states
|
||||
print ('[X] Actual Number of states:', len(memoized.keys()))
|
||||
print ('[X] Number of transitions:', num_transitions)
|
||||
print ('[X] Original Number of states:', len(states))
|
||||
final_struct["numstates"] = len(states)
|
||||
final_struct["pda"] = memoized
|
||||
return final_struct
|
||||
|
||||
# Running FSA construction in exact approximation mode and postprocessing it like so
|
||||
for transition in pda:
|
||||
state = transition["source"]
|
||||
memoized[state].append([transition["trigger"], transition["dest"],
|
||||
transition["terminal"]])
|
||||
|
||||
final_struct["init_state"] = initial
|
||||
final_struct["final_state"] = final[0]
|
||||
print ('[X] Actual Number of states:', len(memoized.keys()))
|
||||
final_struct["numstates"] = len(memoized.keys())
|
||||
final_struct["pda"] = memoized
|
||||
return final_struct
|
||||
|
||||
|
||||
def _get_states():
|
||||
source = set()
|
||||
dest = set()
|
||||
global pda
|
||||
for transition in pda:
|
||||
source.add(transition["source"])
|
||||
dest.add(transition["dest"])
|
||||
source_copy = source.copy()
|
||||
source_copy.update(dest)
|
||||
return list(source_copy), list(dest.difference(source)), str(''.join(list(source.difference(dest))))
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description = 'Script to convert GNF grammar to PDA')
|
||||
parser.add_argument(
|
||||
'--gf',
|
||||
type = str,
|
||||
help = 'Location of GNF grammar')
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
type = int,
|
||||
default = None,
|
||||
help = 'Specify the upper bound for the stack size')
|
||||
args = parser.parse_args()
|
||||
main(args.gf, args.limit)
|
289
custom_mutators/gramatron/preprocess/gnf_converter.py
Normal file
289
custom_mutators/gramatron/preprocess/gnf_converter.py
Normal file
@ -0,0 +1,289 @@
|
||||
import sys
|
||||
import re
|
||||
import copy
|
||||
import json
|
||||
from string import ascii_uppercase
|
||||
from itertools import combinations
|
||||
from collections import defaultdict
|
||||
|
||||
NONTERMINALSET = []
|
||||
COUNT = 1
|
||||
|
||||
def main(grammar_file, out, start):
|
||||
grammar = None
|
||||
# If grammar file is a preprocessed NT file, then skip preprocessing
|
||||
if '.json' in grammar_file:
|
||||
with open(grammar_file, 'r') as fd:
|
||||
grammar = json.load(fd)
|
||||
elif '.g4' in grammar_file:
|
||||
with open(grammar_file, 'r') as fd:
|
||||
data = fd.readlines()
|
||||
grammar = preprocess(data)
|
||||
else:
|
||||
raise('Unknwown file format passed. Accepts (.g4/.json)')
|
||||
|
||||
with open('debug_preprocess.json', 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
grammar = remove_unit(grammar) # eliminates unit productions
|
||||
with open('debug_unit.json', 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
grammar = remove_mixed(grammar) # eliminate terminals existing with non-terminals
|
||||
with open('debug_mixed.json', 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
grammar = break_rules(grammar) # eliminate rules with more than two non-terminals
|
||||
with open('debug_break.json', 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
grammar = gnf(grammar)
|
||||
|
||||
# Dump GNF form of the grammar with only reachable rules
|
||||
# reachable_grammar = get_reachable(grammar, start)
|
||||
# with open('debug_gnf_reachable.json', 'w+') as fd:
|
||||
# json.dump(reachable_grammar, fd)
|
||||
with open('debug_gnf.json', 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
|
||||
grammar["Start"] = [start]
|
||||
with open(out, 'w+') as fd:
|
||||
json.dump(grammar, fd)
|
||||
|
||||
def get_reachable(grammar, start):
|
||||
'''
|
||||
Returns a grammar without dead rules
|
||||
'''
|
||||
reachable_nt = set()
|
||||
worklist = list()
|
||||
processed = set()
|
||||
reachable_grammar = dict()
|
||||
worklist.append(start)
|
||||
|
||||
while worklist:
|
||||
nt = worklist.pop(0)
|
||||
processed.add(nt)
|
||||
reachable_grammar[nt] = grammar[nt]
|
||||
rules = grammar[nt]
|
||||
for rule in rules:
|
||||
tokens = gettokens(rule)
|
||||
for token in tokens:
|
||||
if not isTerminal(token):
|
||||
if token not in processed:
|
||||
worklist.append(token)
|
||||
return reachable_grammar
|
||||
|
||||
|
||||
def gettokens(rule):
|
||||
pattern = re.compile("([^\s\"\']+)|\"([^\"]*)\"|\'([^\']*)\'")
|
||||
return [matched.group(0) for matched in pattern.finditer(rule)]
|
||||
|
||||
def gnf(grammar):
|
||||
old_grammar = copy.deepcopy(grammar)
|
||||
new_grammar = defaultdict(list)
|
||||
isgnf = False
|
||||
while not isgnf:
|
||||
for lhs, rules in old_grammar.items():
|
||||
for rule in rules:
|
||||
tokens = gettokens(rule)
|
||||
if len(tokens) == 1 and isTerminal(rule):
|
||||
new_grammar[lhs].append(rule)
|
||||
continue
|
||||
startoken = tokens[0]
|
||||
endrule = tokens[1:]
|
||||
if not isTerminal(startoken):
|
||||
newrules = []
|
||||
extendrules = old_grammar[startoken]
|
||||
for extension in extendrules:
|
||||
temprule = endrule[:]
|
||||
temprule.insert(0, extension)
|
||||
newrules.append(temprule)
|
||||
for newnew in newrules:
|
||||
new_grammar[lhs].append(' '.join(newnew))
|
||||
else:
|
||||
new_grammar[lhs].append(rule)
|
||||
isgnf = True
|
||||
for lhs, rules in new_grammar.items():
|
||||
for rule in rules:
|
||||
# if "\' \'" or isTerminal(rule):
|
||||
tokens = gettokens(rule)
|
||||
if len(tokens) == 1 and isTerminal(rule):
|
||||
continue
|
||||
startoken = tokens[0]
|
||||
if not isTerminal(startoken):
|
||||
isgnf = False
|
||||
break
|
||||
if not isgnf:
|
||||
old_grammar = copy.deepcopy(new_grammar)
|
||||
new_grammar = defaultdict(list)
|
||||
return new_grammar
|
||||
|
||||
|
||||
def preprocess(data):
|
||||
productions = []
|
||||
production = []
|
||||
for line in data:
|
||||
if line != '\n':
|
||||
production.append(line)
|
||||
else:
|
||||
productions.append(production)
|
||||
production = []
|
||||
final_rule_set = {}
|
||||
for production in productions:
|
||||
rules = []
|
||||
init = production[0]
|
||||
nonterminal = init.split(':')[0]
|
||||
rules.append(strip_chars(init.split(':')[1]).strip('| '))
|
||||
for production_rule in production[1:]:
|
||||
rules.append(strip_chars(production_rule.split('|')[0]))
|
||||
final_rule_set[nonterminal] = rules
|
||||
# for line in data:
|
||||
# if line != '\n':
|
||||
# production.append(line)
|
||||
return final_rule_set
|
||||
|
||||
def remove_unit(grammar):
|
||||
nounitproductions = False
|
||||
old_grammar = copy.deepcopy(grammar)
|
||||
new_grammar = defaultdict(list)
|
||||
while not nounitproductions:
|
||||
for lhs, rules in old_grammar.items():
|
||||
for rhs in rules:
|
||||
# Checking if the rule is a unit production rule
|
||||
if len(gettokens(rhs)) == 1:
|
||||
if not isTerminal(rhs):
|
||||
new_grammar[lhs].extend([rule for rule in old_grammar[rhs]])
|
||||
else:
|
||||
new_grammar[lhs].append(rhs)
|
||||
else:
|
||||
new_grammar[lhs].append(rhs)
|
||||
# Checking there are no unit productions left in the grammar
|
||||
nounitproductions = True
|
||||
for lhs, rules in new_grammar.items():
|
||||
for rhs in rules:
|
||||
if len(gettokens(rhs)) == 1:
|
||||
if not isTerminal(rhs):
|
||||
nounitproductions = False
|
||||
break
|
||||
if not nounitproductions:
|
||||
break
|
||||
# Unit productions are still there in the grammar -- repeat the process
|
||||
if not nounitproductions:
|
||||
old_grammar = copy.deepcopy(new_grammar)
|
||||
new_grammar = defaultdict(list)
|
||||
return new_grammar
|
||||
|
||||
def isTerminal(rule):
|
||||
# pattern = re.compile("([r]*\'[\s\S]+\')")
|
||||
pattern = re.compile("\'(.*?)\'")
|
||||
match = pattern.match(rule)
|
||||
if match:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def remove_mixed(grammar):
|
||||
'''
|
||||
Remove rules where there are terminals mixed in with non-terminals
|
||||
'''
|
||||
new_grammar = defaultdict(list)
|
||||
for lhs, rules in grammar.items():
|
||||
for rhs in rules:
|
||||
# tokens = rhs.split(' ')
|
||||
regen_rule = []
|
||||
tokens = gettokens(rhs)
|
||||
if len(gettokens(rhs)) == 1:
|
||||
new_grammar[lhs].append(rhs)
|
||||
continue
|
||||
for token in tokens:
|
||||
# Identify if there is a terminal in the RHS
|
||||
if isTerminal(token):
|
||||
# Check if a corresponding nonterminal already exists
|
||||
nonterminal = terminal_exist(token, new_grammar)
|
||||
if nonterminal:
|
||||
regen_rule.append(nonterminal)
|
||||
else:
|
||||
new_nonterm = get_nonterminal()
|
||||
new_grammar[new_nonterm].append(token)
|
||||
regen_rule.append(new_nonterm)
|
||||
else:
|
||||
regen_rule.append(token)
|
||||
new_grammar[lhs].append(' '.join(regen_rule))
|
||||
return new_grammar
|
||||
|
||||
def break_rules(grammar):
|
||||
new_grammar = defaultdict(list)
|
||||
old_grammar = copy.deepcopy(grammar)
|
||||
nomulti = False
|
||||
while not nomulti:
|
||||
for lhs, rules in old_grammar.items():
|
||||
for rhs in rules:
|
||||
tokens = gettokens(rhs)
|
||||
if len(tokens) > 2 and (not isTerminal(rhs)):
|
||||
split = tokens[:-1]
|
||||
nonterminal = terminal_exist(' '.join(split), new_grammar)
|
||||
if nonterminal:
|
||||
newrule = ' '.join([nonterminal, tokens[-1]])
|
||||
new_grammar[lhs].append(newrule)
|
||||
else:
|
||||
nonterminal = get_nonterminal()
|
||||
new_grammar[nonterminal].append(' '.join(split))
|
||||
newrule = ' '.join([nonterminal, tokens[-1]])
|
||||
new_grammar[lhs].append(newrule)
|
||||
else:
|
||||
new_grammar[lhs].append(rhs)
|
||||
nomulti = True
|
||||
for lhs, rules in new_grammar.items():
|
||||
for rhs in rules:
|
||||
# tokens = rhs.split(' ')
|
||||
tokens = gettokens(rhs)
|
||||
if len(tokens) > 2 and (not isTerminal(rhs)):
|
||||
nomulti = False
|
||||
break
|
||||
if not nomulti:
|
||||
old_grammar = copy.deepcopy(new_grammar)
|
||||
new_grammar = defaultdict(list)
|
||||
return new_grammar
|
||||
|
||||
def strip_chars(rule):
|
||||
return rule.strip('\n\t ')
|
||||
|
||||
def get_nonterminal():
|
||||
global NONTERMINALSET
|
||||
if NONTERMINALSET:
|
||||
return NONTERMINALSET.pop(0)
|
||||
else:
|
||||
_repopulate()
|
||||
return NONTERMINALSET.pop(0)
|
||||
|
||||
def _repopulate():
|
||||
global COUNT
|
||||
global NONTERMINALSET
|
||||
NONTERMINALSET = [''.join(x) for x in list(combinations(ascii_uppercase, COUNT))]
|
||||
COUNT += 1
|
||||
|
||||
def terminal_exist(token, grammar):
|
||||
for nonterminal, rules in grammar.items():
|
||||
if token in rules:
|
||||
return nonterminal
|
||||
return None
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description = 'Script to convert grammar to GNF form')
|
||||
parser.add_argument(
|
||||
'--gf',
|
||||
type = str,
|
||||
required = True,
|
||||
help = 'Location of grammar file')
|
||||
parser.add_argument(
|
||||
'--out',
|
||||
type = str,
|
||||
required = True,
|
||||
help = 'Location of output file')
|
||||
parser.add_argument(
|
||||
'--start',
|
||||
type = str,
|
||||
required = True,
|
||||
help = 'Start token')
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.gf, args.out, args.start)
|
38
custom_mutators/gramatron/preprocess/prep_automaton.sh
Executable file
38
custom_mutators/gramatron/preprocess/prep_automaton.sh
Executable file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script creates a FSA describing the input grammar *.g4
|
||||
|
||||
if [ ! "$#" -lt 4 ]; then
|
||||
echo "Usage: ./prep_pda.sh <grammar_file> <start> [stack_limit]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GRAMMAR_FILE=$1
|
||||
GRAMMAR_DIR="$(dirname $GRAMMAR_FILE)"
|
||||
START="$2"
|
||||
STACK_LIMIT="$3"
|
||||
|
||||
# Get filename
|
||||
FILE=$(basename -- "$GRAMMAR_FILE")
|
||||
echo "File:$FILE"
|
||||
FILENAME="${FILE%.*}"
|
||||
echo "Name:$FILENAME"
|
||||
|
||||
|
||||
# Create the GNF form of the grammar
|
||||
CMD="python gnf_converter.py --gf $GRAMMAR_FILE --out ${FILENAME}.json --start $START"
|
||||
$CMD
|
||||
|
||||
# Generate grammar automaton
|
||||
# Check if user provided a stack limit
|
||||
if [ -z "${STACK_LIMIT}" ]; then
|
||||
CMD="python3 construct_automata.py --gf ${FILENAME}.json"
|
||||
else
|
||||
CMD="python construct_automata.py --gf ${FILENAME}.json --limit ${STACK_LIMIT}"
|
||||
fi
|
||||
echo $CMD
|
||||
$CMD
|
||||
|
||||
# Move PDA to the source dir of the grammar
|
||||
echo "Copying ${FILENAME}_automata.json to $GRAMMAR_DIR"
|
||||
mv "${FILENAME}_automata.json" $GRAMMAR_DIR/
|
154
custom_mutators/gramatron/test.c
Normal file
154
custom_mutators/gramatron/test.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* This is the testing module for Gramatron
|
||||
*/
|
||||
#include "afl-fuzz.h"
|
||||
#include "gramfuzz.h"
|
||||
|
||||
#define NUMINPUTS 50
|
||||
|
||||
state *create_pda(u8 *automaton_file) {
|
||||
|
||||
struct json_object *parsed_json;
|
||||
state * pda;
|
||||
json_object * source_obj, *attr;
|
||||
int arraylen, ii, ii2, trigger_len, error;
|
||||
|
||||
printf("\n[GF] Automaton file passed:%s", automaton_file);
|
||||
// parsed_json =
|
||||
// json_object_from_file("./gramfuzz/php_gnf_processed_full.json");
|
||||
parsed_json = json_object_from_file(automaton_file);
|
||||
|
||||
// Getting final state
|
||||
source_obj = json_object_object_get(parsed_json, "final_state");
|
||||
printf("\t\nFinal=%s\n", json_object_get_string(source_obj));
|
||||
final_state = atoi(json_object_get_string(source_obj));
|
||||
|
||||
// Getting initial state
|
||||
source_obj = json_object_object_get(parsed_json, "init_state");
|
||||
init_state = atoi(json_object_get_string(source_obj));
|
||||
printf("\tInit=%s\n", json_object_get_string(source_obj));
|
||||
|
||||
// Getting number of states
|
||||
source_obj = json_object_object_get(parsed_json, "numstates");
|
||||
numstates = atoi(json_object_get_string(source_obj)) + 1;
|
||||
printf("\tNumStates=%d\n", numstates);
|
||||
|
||||
// Allocate state space for each pda state
|
||||
pda = (state *)calloc(atoi(json_object_get_string(source_obj)) + 1,
|
||||
sizeof(state));
|
||||
|
||||
// Getting PDA representation
|
||||
source_obj = json_object_object_get(parsed_json, "pda");
|
||||
enum json_type type;
|
||||
json_object_object_foreach(source_obj, key, val) {
|
||||
|
||||
state * state_ptr;
|
||||
trigger *trigger_ptr;
|
||||
int offset;
|
||||
|
||||
// Get the correct offset into the pda to store state information
|
||||
state_ptr = pda;
|
||||
offset = atoi(key);
|
||||
state_ptr += offset;
|
||||
|
||||
// Store state string
|
||||
state_ptr->state_name = offset;
|
||||
|
||||
// Create trigger array of structs
|
||||
trigger_len = json_object_array_length(val);
|
||||
state_ptr->trigger_len = trigger_len;
|
||||
trigger_ptr = (trigger *)calloc(trigger_len, sizeof(trigger));
|
||||
state_ptr->ptr = trigger_ptr;
|
||||
printf("\nName:%d Trigger:%d", offset, trigger_len);
|
||||
|
||||
for (ii = 0; ii < trigger_len; ii++) {
|
||||
|
||||
json_object *obj = json_object_array_get_idx(val, ii);
|
||||
// Get all the trigger trigger attributes
|
||||
attr = json_object_array_get_idx(obj, 0);
|
||||
(trigger_ptr)->id = strdup(json_object_get_string(attr));
|
||||
|
||||
attr = json_object_array_get_idx(obj, 1);
|
||||
trigger_ptr->dest = atoi(json_object_get_string(attr));
|
||||
|
||||
attr = json_object_array_get_idx(obj, 2);
|
||||
if (!strcmp("\\n", json_object_get_string(attr))) {
|
||||
|
||||
trigger_ptr->term = strdup("\n");
|
||||
|
||||
} else {
|
||||
|
||||
trigger_ptr->term = strdup(json_object_get_string(attr));
|
||||
|
||||
}
|
||||
|
||||
trigger_ptr->term_len = strlen(trigger_ptr->term);
|
||||
trigger_ptr++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Delete the JSON object
|
||||
json_object_put(parsed_json);
|
||||
|
||||
return pda;
|
||||
|
||||
}
|
||||
|
||||
void SanityCheck(char *automaton_path) {
|
||||
|
||||
state * pda = create_pda(automaton_path);
|
||||
int count = 0, state;
|
||||
Get_Dupes_Ret *getdupesret;
|
||||
IdxMap_new * statemap;
|
||||
IdxMap_new * statemap_ptr;
|
||||
terminal * term_ptr;
|
||||
|
||||
while (count < NUMINPUTS) {
|
||||
|
||||
// Perform input generation
|
||||
Array *generated = gen_input(pda, NULL);
|
||||
print_repr(generated, "Gen");
|
||||
count += 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
char * mode;
|
||||
char * automaton_path;
|
||||
char * output_dir = NULL;
|
||||
struct timeval tv;
|
||||
struct timeval tz;
|
||||
// gettimeofday(&tv, &tz);
|
||||
srand(1337);
|
||||
if (argc == 3) {
|
||||
|
||||
mode = argv[1];
|
||||
automaton_path = strdup(argv[2]);
|
||||
printf("\nMode:%s Path:%s", mode, automaton_path);
|
||||
|
||||
} else {
|
||||
|
||||
printf("\nUsage: ./test <mode> <automaton_path>");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(mode, "SanityCheck")) {
|
||||
|
||||
SanityCheck(automaton_path);
|
||||
|
||||
} else {
|
||||
|
||||
printf("\nUnrecognized mode");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
57
custom_mutators/gramatron/test.h
Normal file
57
custom_mutators/gramatron/test.h
Normal file
@ -0,0 +1,57 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <json-c/json.h>
|
||||
#include <unistd.h>
|
||||
#include "hashmap.h"
|
||||
#include "uthash.h"
|
||||
#include "utarray.h"
|
||||
|
||||
#define INIT_SIZE 100 // Initial size of the dynamic array holding the input
|
||||
|
||||
typedef struct terminal {
|
||||
|
||||
int state;
|
||||
int trigger_idx;
|
||||
size_t symbol_len;
|
||||
char * symbol;
|
||||
|
||||
} terminal;
|
||||
|
||||
typedef struct trigger {
|
||||
|
||||
char * id;
|
||||
int dest;
|
||||
char * term;
|
||||
size_t term_len;
|
||||
|
||||
} trigger;
|
||||
|
||||
typedef struct state {
|
||||
|
||||
int state_name; // Integer State name
|
||||
int trigger_len; // Number of triggers associated with this state
|
||||
trigger *ptr; // Pointer to beginning of the list of triggers
|
||||
|
||||
} state;
|
||||
|
||||
typedef struct {
|
||||
|
||||
size_t used;
|
||||
size_t size;
|
||||
size_t inputlen;
|
||||
terminal *start;
|
||||
|
||||
} Array;
|
||||
|
||||
int init_state;
|
||||
int curr_state;
|
||||
int final_state;
|
||||
|
||||
state *create_pda(char *);
|
||||
Array *gen_input(state *, Array *);
|
||||
void print_repr(Array *, char *);
|
||||
void initArray(Array *, size_t);
|
||||
void insertArray(Array *, int, char *, size_t, int);
|
||||
|
392
custom_mutators/gramatron/utarray.h
Normal file
392
custom_mutators/gramatron/utarray.h
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a dynamic array implementation using macros
|
||||
*/
|
||||
#ifndef UTARRAY_H
|
||||
#define UTARRAY_H
|
||||
|
||||
#define UTARRAY_VERSION 2.1.0
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <string.h> /* memset, etc */
|
||||
#include <stdlib.h> /* exit */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UTARRAY_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define UTARRAY_UNUSED
|
||||
#endif
|
||||
|
||||
#ifdef oom
|
||||
#error \
|
||||
"The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code."
|
||||
#define utarray_oom() oom()
|
||||
#endif
|
||||
|
||||
#ifndef utarray_oom
|
||||
#define utarray_oom() exit(-1)
|
||||
#endif
|
||||
|
||||
typedef void(ctor_f)(void *dst, const void *src);
|
||||
typedef void(dtor_f)(void *elt);
|
||||
typedef void(init_f)(void *elt);
|
||||
typedef struct {
|
||||
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
|
||||
} UT_icd;
|
||||
|
||||
typedef struct {
|
||||
|
||||
unsigned i, n; /* i: index of next available slot, n: num slots */
|
||||
UT_icd icd; /* initializer, copy and destructor functions */
|
||||
char * d; /* n slots of size icd->sz*/
|
||||
|
||||
} UT_array;
|
||||
|
||||
#define utarray_init(a, _icd) \
|
||||
do { \
|
||||
\
|
||||
memset(a, 0, sizeof(UT_array)); \
|
||||
(a)->icd = *(_icd); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_done(a) \
|
||||
do { \
|
||||
\
|
||||
if ((a)->n) { \
|
||||
\
|
||||
if ((a)->icd.dtor) { \
|
||||
\
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \
|
||||
\
|
||||
(a)->icd.dtor(utarray_eltptr(a, _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
free((a)->d); \
|
||||
\
|
||||
} \
|
||||
(a)->n = 0; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_new(a, _icd) \
|
||||
do { \
|
||||
\
|
||||
(a) = (UT_array *)malloc(sizeof(UT_array)); \
|
||||
if ((a) == NULL) { utarray_oom(); } \
|
||||
utarray_init(a, _icd); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_free(a) \
|
||||
do { \
|
||||
\
|
||||
utarray_done(a); \
|
||||
free(a); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_reserve(a, by) \
|
||||
do { \
|
||||
\
|
||||
if (((a)->i + (by)) > (a)->n) { \
|
||||
\
|
||||
char *utarray_tmp; \
|
||||
while (((a)->i + (by)) > (a)->n) { \
|
||||
\
|
||||
(a)->n = ((a)->n ? (2 * (a)->n) : 8); \
|
||||
\
|
||||
} \
|
||||
utarray_tmp = (char *)realloc((a)->d, (a)->n * (a)->icd.sz); \
|
||||
if (utarray_tmp == NULL) { utarray_oom(); } \
|
||||
(a)->d = utarray_tmp; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_push_back(a, p) \
|
||||
do { \
|
||||
\
|
||||
utarray_reserve(a, 1); \
|
||||
if ((a)->icd.copy) { \
|
||||
\
|
||||
(a)->icd.copy(_utarray_eltptr(a, (a)->i++), p); \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
memcpy(_utarray_eltptr(a, (a)->i++), p, (a)->icd.sz); \
|
||||
\
|
||||
}; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_pop_back(a) \
|
||||
do { \
|
||||
\
|
||||
if ((a)->icd.dtor) { \
|
||||
\
|
||||
(a)->icd.dtor(_utarray_eltptr(a, --((a)->i))); \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
(a)->i--; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_extend_back(a) \
|
||||
do { \
|
||||
\
|
||||
utarray_reserve(a, 1); \
|
||||
if ((a)->icd.init) { \
|
||||
\
|
||||
(a)->icd.init(_utarray_eltptr(a, (a)->i)); \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
memset(_utarray_eltptr(a, (a)->i), 0, (a)->icd.sz); \
|
||||
\
|
||||
} \
|
||||
(a)->i++; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_len(a) ((a)->i)
|
||||
|
||||
#define utarray_eltptr(a, j) (((j) < (a)->i) ? _utarray_eltptr(a, j) : NULL)
|
||||
#define _utarray_eltptr(a, j) ((a)->d + ((a)->icd.sz * (j)))
|
||||
|
||||
#define utarray_insert(a, p, j) \
|
||||
do { \
|
||||
\
|
||||
if ((j) > (a)->i) utarray_resize(a, j); \
|
||||
utarray_reserve(a, 1); \
|
||||
if ((j) < (a)->i) { \
|
||||
\
|
||||
memmove(_utarray_eltptr(a, (j) + 1), _utarray_eltptr(a, j), \
|
||||
((a)->i - (j)) * ((a)->icd.sz)); \
|
||||
\
|
||||
} \
|
||||
if ((a)->icd.copy) { \
|
||||
\
|
||||
(a)->icd.copy(_utarray_eltptr(a, j), p); \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
memcpy(_utarray_eltptr(a, j), p, (a)->icd.sz); \
|
||||
\
|
||||
}; \
|
||||
(a)->i++; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_inserta(a, w, j) \
|
||||
do { \
|
||||
\
|
||||
if (utarray_len(w) == 0) break; \
|
||||
if ((j) > (a)->i) utarray_resize(a, j); \
|
||||
utarray_reserve(a, utarray_len(w)); \
|
||||
if ((j) < (a)->i) { \
|
||||
\
|
||||
memmove(_utarray_eltptr(a, (j) + utarray_len(w)), _utarray_eltptr(a, j), \
|
||||
((a)->i - (j)) * ((a)->icd.sz)); \
|
||||
\
|
||||
} \
|
||||
if ((a)->icd.copy) { \
|
||||
\
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (w)->i; _ut_i++) { \
|
||||
\
|
||||
(a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), \
|
||||
_utarray_eltptr(w, _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
memcpy(_utarray_eltptr(a, j), _utarray_eltptr(w, 0), \
|
||||
utarray_len(w) * ((a)->icd.sz)); \
|
||||
\
|
||||
} \
|
||||
(a)->i += utarray_len(w); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_resize(dst, num) \
|
||||
do { \
|
||||
\
|
||||
unsigned _ut_i; \
|
||||
if ((dst)->i > (unsigned)(num)) { \
|
||||
\
|
||||
if ((dst)->icd.dtor) { \
|
||||
\
|
||||
for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \
|
||||
\
|
||||
(dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} else if ((dst)->i < (unsigned)(num)) { \
|
||||
\
|
||||
utarray_reserve(dst, (num) - (dst)->i); \
|
||||
if ((dst)->icd.init) { \
|
||||
\
|
||||
for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \
|
||||
\
|
||||
(dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
memset(_utarray_eltptr(dst, (dst)->i), 0, \
|
||||
(dst)->icd.sz *((num) - (dst)->i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
(dst)->i = (num); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_concat(dst, src) \
|
||||
do { \
|
||||
\
|
||||
utarray_inserta(dst, src, utarray_len(dst)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_erase(a, pos, len) \
|
||||
do { \
|
||||
\
|
||||
if ((a)->icd.dtor) { \
|
||||
\
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (len); _ut_i++) { \
|
||||
\
|
||||
(a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
if ((a)->i > ((pos) + (len))) { \
|
||||
\
|
||||
memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \
|
||||
((a)->i - ((pos) + (len))) * (a)->icd.sz); \
|
||||
\
|
||||
} \
|
||||
(a)->i -= (len); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_renew(a, u) \
|
||||
do { \
|
||||
\
|
||||
if (a) \
|
||||
utarray_clear(a); \
|
||||
else \
|
||||
utarray_new(a, u); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_clear(a) \
|
||||
do { \
|
||||
\
|
||||
if ((a)->i > 0) { \
|
||||
\
|
||||
if ((a)->icd.dtor) { \
|
||||
\
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \
|
||||
\
|
||||
(a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
(a)->i = 0; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_sort(a, cmp) \
|
||||
do { \
|
||||
\
|
||||
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define utarray_find(a, v, cmp) bsearch((v), (a)->d, (a)->i, (a)->icd.sz, cmp)
|
||||
|
||||
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a, 0)) : NULL)
|
||||
#define utarray_next(a, e) \
|
||||
(((e) == NULL) ? utarray_front(a) \
|
||||
: (((a)->i != utarray_eltidx(a, e) + 1) \
|
||||
? _utarray_eltptr(a, utarray_eltidx(a, e) + 1) \
|
||||
: NULL))
|
||||
#define utarray_prev(a, e) \
|
||||
(((e) == NULL) ? utarray_back(a) \
|
||||
: ((utarray_eltidx(a, e) != 0) \
|
||||
? _utarray_eltptr(a, utarray_eltidx(a, e) - 1) \
|
||||
: NULL))
|
||||
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a, (a)->i - 1)) : NULL)
|
||||
#define utarray_eltidx(a, e) (((char *)(e) - (a)->d) / (a)->icd.sz)
|
||||
|
||||
/* last we pre-define a few icd for common utarrays of ints and strings */
|
||||
static void utarray_str_cpy(void *dst, const void *src) {
|
||||
|
||||
char **_src = (char **)src, **_dst = (char **)dst;
|
||||
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
|
||||
|
||||
}
|
||||
|
||||
static void utarray_str_dtor(void *elt) {
|
||||
|
||||
char **eltc = (char **)elt;
|
||||
if (*eltc != NULL) free(*eltc);
|
||||
|
||||
}
|
||||
|
||||
static const UT_icd ut_str_icd UTARRAY_UNUSED = {
|
||||
|
||||
sizeof(char *), NULL, utarray_str_cpy, utarray_str_dtor};
|
||||
static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int), NULL, NULL, NULL};
|
||||
static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void *), NULL, NULL,
|
||||
NULL};
|
||||
|
||||
#endif /* UTARRAY_H */
|
||||
|
1611
custom_mutators/gramatron/uthash.h
Normal file
1611
custom_mutators/gramatron/uthash.h
Normal file
File diff suppressed because it is too large
Load Diff
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 b3c4fcfa6a
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
|
||||
|
146
custom_mutators/honggfuzz/honggfuzz.c
Normal file
146
custom_mutators/honggfuzz/honggfuzz.c
Normal file
@ -0,0 +1,146 @@
|
||||
#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 */
|
||||
|
||||
uint8_t 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++;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
}
|
||||
|
387
custom_mutators/honggfuzz/honggfuzz.h
Normal file
387
custom_mutators/honggfuzz/honggfuzz.h
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
*
|
||||
* 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[512];
|
||||
size_t len;
|
||||
} dictionary[8192];
|
||||
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;
|
||||
uint8_t exitCodeUponCrash;
|
||||
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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user