mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
981 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
@ -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
|
||||
|
@ -29,14 +29,14 @@ CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
|
||||
if CLANG_FORMAT_BIN is None:
|
||||
o = 0
|
||||
try:
|
||||
p = subprocess.Popen(["clang-format-8", "--version"], stdout=subprocess.PIPE)
|
||||
p = subprocess.Popen(["clang-format-10", "--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)
|
||||
except:
|
||||
print ("clang-format-8 is needed. Aborted.")
|
||||
print ("clang-format-10 is needed. Aborted.")
|
||||
exit(1)
|
||||
#if o < 7:
|
||||
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
|
||||
@ -51,7 +51,7 @@ if CLANG_FORMAT_BIN is None:
|
||||
# print ("clang-format 7 or above is needed. Aborted.")
|
||||
# exit(1)
|
||||
else:
|
||||
CLANG_FORMAT_BIN = 'clang-format-8'
|
||||
CLANG_FORMAT_BIN = 'clang-format-10'
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
@ -70,8 +70,8 @@ def custom_format(filename):
|
||||
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):
|
||||
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -8,19 +8,26 @@ afl-clang
|
||||
afl-clang++
|
||||
afl-clang-fast
|
||||
afl-clang-fast++
|
||||
afl-clang-lto
|
||||
afl-clang-lto++
|
||||
afl-fuzz
|
||||
afl-g++
|
||||
afl-gcc
|
||||
afl-gcc-fast
|
||||
afl-g++-fast
|
||||
afl-gotcpu
|
||||
afl-ld
|
||||
afl-qemu-trace
|
||||
afl-showmap
|
||||
afl-tmin
|
||||
afl-analyze.8
|
||||
afl-as.8
|
||||
afl-clang-fast++.8
|
||||
afl-clang-fast.8
|
||||
afl-clang-lto.8
|
||||
afl-clang-lto++.8
|
||||
afl-cmin.8
|
||||
afl-cmin.bash.8
|
||||
afl-fuzz.8
|
||||
afl-gcc.8
|
||||
afl-gcc-fast.8
|
||||
@ -33,8 +40,13 @@ afl-tmin.8
|
||||
afl-whatsup.8
|
||||
qemu_mode/libcompcov/compcovtest
|
||||
as
|
||||
ld
|
||||
qemu_mode/qemu-*
|
||||
unicorn_mode/unicornafl/
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
core\.*
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
examples/afl_network_proxy/afl-network-server
|
||||
examples/afl_network_proxy/afl-network-client
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "unicorn_mode/unicornafl"]
|
||||
path = unicorn_mode/unicornafl
|
||||
url = https://github.com/AFLplusplus/unicornafl.git
|
13
.travis.yml
13
.travis.yml
@ -5,9 +5,13 @@ sudo: required
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: focal
|
||||
env: NAME="focal-amd64" MODERN="yes" GCC="9"
|
||||
- os: linux
|
||||
dist: bionic
|
||||
env: NAME="bionic-amd64" MODERN="yes" GCC="7"
|
||||
@ -28,9 +32,10 @@ matrix:
|
||||
jobs:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- arch: arm64
|
||||
|
||||
env:
|
||||
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_STOP_MANUALLY=1
|
||||
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1
|
||||
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_EXIT_WHEN_DONE=1
|
||||
# TODO: test AFL_BENCH_UNTIL_CRASH once we have a target that crashes
|
||||
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_BENCH_JUST_ONE=1
|
||||
@ -39,8 +44,8 @@ before_install:
|
||||
# export LLVM_DIR=${TRAVIS_BUILD_DIR}/${LLVM_PACKAGE}
|
||||
- echo Testing on $NAME
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then wget "$LINK""$NAME".tar.xz ; export LLVM_CONFIG=`pwd`/"$NAME" ; tar xJf "$NAME".tar.xz ; fi
|
||||
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y libtool libtool-bin automake bison libglib2.0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils ; fi
|
||||
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils ; fi
|
||||
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y git libtool libtool-bin automake bison libglib2.0-0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev python3-setuptools ; fi
|
||||
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y git libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils libcmocka-dev python3-setuptools ; fi
|
||||
|
||||
script:
|
||||
- gcc -v
|
||||
@ -50,4 +55,4 @@ script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$TRAVIS_CPU_ARCH" = "amd64" ]; then make distrib ASAN_BUILD=1 ; fi
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then echo DEBUG ; find / -name llvm-config.h 2>/dev/null; apt-cache search clang | grep clang- ; apt-cache search llvm | grep llvm- ; dpkg -l | egrep 'clang|llvm'; echo DEBUG ; export LLVM_CONFIG=llvm-config-6.0 ; make ASAN_BUILD=1 ; cd qemu_mode && sh ./build_qemu_support.sh ; cd .. ; fi
|
||||
- make tests
|
||||
- travis_terminate 0
|
||||
# - travis_terminate 0
|
||||
|
@ -3,17 +3,20 @@
|
||||
Each modified source file, before merging, must be formatted.
|
||||
|
||||
```
|
||||
make code-formatter
|
||||
make code-format
|
||||
```
|
||||
|
||||
This should be fine if you modified one of the files already present in the
|
||||
project, otherwise run:
|
||||
project, or added a file in a directory we already format, otherwise run:
|
||||
|
||||
```
|
||||
./.custom-format.py -i file-that-you-have-created.c
|
||||
```
|
||||
|
||||
Regarding the coding style, please follow the AFL style.
|
||||
No camel case at all and use the AFL's macros when possible (e.g. WARNF, FATAL, ...).
|
||||
No camel case at all and use the AFL's macros wherever possible
|
||||
(e.g. WARNF, FATAL, MAP_SIZE, ...).
|
||||
|
||||
Remember that AFLplusplus has to build and run on many platforms, so generalize your Makefiles (or your patches to our pre-existing Makefiles) to be as much general as possible.
|
||||
Remember that AFLplusplus has to build and run on many platforms, so
|
||||
generalize your Makefiles (or your patches to our pre-existing Makefiles)
|
||||
to be as much generic as possible.
|
||||
|
12
Dockerfile
12
Dockerfile
@ -1,4 +1,4 @@
|
||||
FROM ubuntu:eoan
|
||||
FROM ubuntu
|
||||
MAINTAINER David Carlier <devnexen@gmail.com>
|
||||
LABEL "about"="AFLplusplus docker image"
|
||||
RUN apt-get update && apt-get -y install \
|
||||
@ -10,8 +10,10 @@ RUN apt-get update && apt-get -y install \
|
||||
clang-9 \
|
||||
flex \
|
||||
git \
|
||||
python3.7 \
|
||||
python3.7-dev \
|
||||
python3 \
|
||||
python3-dev \
|
||||
python3-setuptools \
|
||||
python-is-python3 \
|
||||
gcc-9 \
|
||||
gcc-9-plugin-dev \
|
||||
gcc-9-multilib \
|
||||
@ -20,8 +22,6 @@ RUN apt-get update && apt-get -y install \
|
||||
libtool-bin \
|
||||
libglib2.0-dev \
|
||||
llvm-9-dev \
|
||||
python-setuptools \
|
||||
python2.7-dev \
|
||||
wget \
|
||||
ca-certificates \
|
||||
libpixman-1-dev \
|
||||
@ -31,7 +31,7 @@ ARG CC=gcc-9
|
||||
ARG CXX=g++-9
|
||||
ARG LLVM_CONFIG=llvm-config-9
|
||||
|
||||
RUN git clone https://github.com/vanhauser-thc/AFLplusplus
|
||||
RUN git clone https://github.com/AFLplusplus/AFLplusplus
|
||||
|
||||
RUN cd AFLplusplus && make clean && make distrib && \
|
||||
make install && cd .. && rm -rf AFLplusplus
|
||||
|
563
GNUmakefile
Normal file
563
GNUmakefile
Normal file
@ -0,0 +1,563 @@
|
||||
#
|
||||
# american fuzzy lop++ - makefile
|
||||
# -----------------------------
|
||||
#
|
||||
# Originally written by Michal Zalewski
|
||||
#
|
||||
# Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
# the hash character is treated differently in different make versions
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||
|
||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_OPT += -march=native
|
||||
endif
|
||||
# OS X does not like _FORTIFY_SOURCE=2
|
||||
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
|
||||
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
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
ifneq "$(shell uname -m)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
|
||||
-I include/ -Werror -DAFL_PATH=\"$(HELPER_PATH)\" \
|
||||
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
|
||||
|
||||
ifeq "$(shell uname -s)" "OpenBSD"
|
||||
override CFLAGS += -I /usr/local/include/
|
||||
LDFLAGS += -L /usr/local/lib/
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname -s)" "NetBSD"
|
||||
override CFLAGS += -I /usr/pkg/include/
|
||||
LDFLAGS += -L /usr/pkg/lib/
|
||||
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%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef 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
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
$(info Compiling ASAN version of binaries)
|
||||
CFLAGS+=$(ASAN_CFLAGS)
|
||||
LDFLAGS+=$(ASAN_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
|
||||
man: $(MANPAGES)
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
@rm -f test/errors
|
||||
|
||||
performance-tests: performance-test
|
||||
test-performance: performance-test
|
||||
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
# hint: make targets are also listed in the top level README.md
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap, radamsa"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything 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 PROFILING - compile afl-fuzz with profiling information
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
radamsa: src/third_party/libradamsa/libradamsa.so
|
||||
cp src/third_party/libradamsa/libradamsa.so .
|
||||
|
||||
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
||||
$(MAKE) -C src/third_party/libradamsa/ CFLAGS="$(CFLAGS)"
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
|
||||
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
|
||||
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_maybe_alloc
|
||||
|
||||
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
|
||||
unit_list: test/unittests/unit_list.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_list
|
||||
|
||||
test/unittests/preallocable.o : $(COMM_HDR) include/afl-prealloc.h test/unittests/preallocable.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CFLAGS_FLTO) -c test/unittests/preallocable.c -o test/unittests/preallocable.o
|
||||
|
||||
unit_preallocable: test/unittests/unit_preallocable.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_preallocable
|
||||
|
||||
unit_clean:
|
||||
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
|
||||
|
||||
ifneq "$(shell uname)" "Darwin"
|
||||
|
||||
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean
|
||||
|
||||
else
|
||||
|
||||
unit:
|
||||
@echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
|
||||
|
||||
endif
|
||||
|
||||
code-format:
|
||||
./.custom-format.py -i src/*.c
|
||||
./.custom-format.py -i include/*.h
|
||||
./.custom-format.py -i libdislocator/*.c
|
||||
./.custom-format.py -i libtokencap/*.c
|
||||
./.custom-format.py -i llvm_mode/*.c
|
||||
./.custom-format.py -i llvm_mode/*.h
|
||||
./.custom-format.py -i llvm_mode/*.cc
|
||||
./.custom-format.py -i gcc_plugin/*.c
|
||||
#./.custom-format.py -i gcc_plugin/*.h
|
||||
./.custom-format.py -i gcc_plugin/*.cc
|
||||
./.custom-format.py -i examples/*/*.c
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i test/*.c
|
||||
./.custom-format.py -i qemu_mode/patches/*.h
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qbdi_mode/*.c
|
||||
./.custom-format.py -i qbdi_mode/*.cpp
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
else
|
||||
|
||||
test_build: afl-gcc afl-as afl-showmap
|
||||
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
all_done: test_build
|
||||
@if [ ! "`type clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.md for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean all
|
||||
|
||||
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-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-*
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/afl_network_proxy clean
|
||||
$(MAKE) -C examples/socket_fuzzing clean
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C src/third_party/libradamsa/ clean
|
||||
rm -rf qemu_mode/qemu-3.1.1
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
else
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
endif
|
||||
|
||||
deepclean: clean
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
git reset --hard >/dev/null 2>&1 || true
|
||||
|
||||
distrib: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/afl_network_proxy
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
binary-only: all radamsa
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/afl_network_proxy
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
source-only: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
#$(MAKE) -C examples/afl_network_proxy
|
||||
#$(MAKE) -C examples/socket_fuzzing
|
||||
#$(MAKE) -C examples/argv_fuzzing
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -hh 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
install: all $(MANPAGES)
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libradamsa.so ]; then set -e; install -m 755 libradamsa.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
|
||||
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
|
||||
if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
|
||||
|
||||
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
459
Makefile
459
Makefile
@ -1,447 +1,42 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
all:
|
||||
@echo trying to use GNU make...
|
||||
@gmake all
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
# the hash character is treated differently in different make versions
|
||||
# so use a variable for '#'
|
||||
HASH=\#
|
||||
source-only:
|
||||
@gmake source-only
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
binary-only:
|
||||
@gmake binary-only
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
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-cmin.bash afl-whatsup afl-system-config
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
|
||||
install:
|
||||
@gmake install
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_OPT = -march=native
|
||||
endif
|
||||
|
||||
ifneq "$(shell uname -m)" "x86_64"
|
||||
ifneq "$(shell uname -m)" "i386"
|
||||
ifneq "$(shell uname -m)" "amd64"
|
||||
ifneq "$(shell uname -m)" "i86pc"
|
||||
AFL_NO_X86=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||
override CFLAGS += -Wall -g -Wno-pointer-sign -I include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function -fcommon
|
||||
|
||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||
|
||||
ifneq "$(shell which python3m)" ""
|
||||
ifneq "$(shell which python3m-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3m-config --libs --embed)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3m-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell which python3)" ""
|
||||
ifneq "$(shell which python3-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python3-config --includes)
|
||||
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
|
||||
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
|
||||
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
|
||||
PYTHON_LIB ?= $(shell python3-config --libs --embed)
|
||||
else
|
||||
PYTHON_LIB ?= $(shell python3-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq "$(shell which python)" ""
|
||||
ifneq "$(shell which python-config)" ""
|
||||
PYTHON_INCLUDE ?= $(shell python-config --includes)
|
||||
PYTHON_LIB ?= $(shell python-config --ldflags)
|
||||
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
else
|
||||
BUILD_DATE ?= $(shell date "+%Y-%m-%d")
|
||||
endif
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
ifneq "$(findstring FreeBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifneq "$(findstring NetBSD, $(shell uname))" ""
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
TEST_CC = afl-gcc
|
||||
else
|
||||
TEST_CC = afl-clang
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
PYFLAGS=-DUSE_PYTHON $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) -DPYTHON_VERSION="\"$(PYTHON_VERSION)\""
|
||||
else
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
endif
|
||||
|
||||
ifdef STATIC
|
||||
$(info Compiling static version of binaries)
|
||||
# Disable python for static compilation to simplify things
|
||||
PYTHON_OK=0
|
||||
PYFLAGS=
|
||||
|
||||
CFLAGS += -static
|
||||
LDFLAGS += -lm -lrt -lpthread -lz -lutil
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS+=-Wno-deprecated-declarations -lrt
|
||||
endif
|
||||
|
||||
ifdef ASAN_BUILD
|
||||
CFLAGS+=-fsanitize=address
|
||||
LDFLAGS+=-fsanitize=address
|
||||
endif
|
||||
|
||||
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
|
||||
|
||||
man: $(MANPAGES)
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
|
||||
tests: source-only
|
||||
@cd test ; ./test.sh
|
||||
@rm -f test/errors
|
||||
|
||||
performance-tests: performance-test
|
||||
test-performance: performance-test
|
||||
|
||||
performance-test: source-only
|
||||
@cd test ; ./test-performance.sh
|
||||
|
||||
|
||||
help:
|
||||
@echo "HELP --- the following make targets exist:"
|
||||
@echo "=========================================="
|
||||
@echo "all: just the main afl++ binaries"
|
||||
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa"
|
||||
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap, radamsa"
|
||||
@echo "distrib: everything (for both binary-only and source code fuzzing)"
|
||||
@echo "man: creates simple man pages from the help option of the programs"
|
||||
@echo "install: installs everything you have compiled with the build option above"
|
||||
@echo "clean: cleans everything. for qemu_mode it means it deletes all downloads as well"
|
||||
@echo "code-format: format the code, do this before you commit and send a PR please!"
|
||||
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
|
||||
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
|
||||
@echo "help: shows these build options :-)"
|
||||
@echo "=========================================="
|
||||
@echo "Recommended: \"distrib\" or \"source-only\", then \"install\""
|
||||
@echo
|
||||
@echo Known build environment options:
|
||||
@echo "=========================================="
|
||||
@echo STATIC - compile AFL++ static
|
||||
@echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
|
||||
ifndef AFL_NO_X86
|
||||
|
||||
test_x86:
|
||||
@echo "[*] Checking for the default compiler cc..."
|
||||
@which $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
|
||||
@echo "[*] Checking for the ability to compile x86 code..."
|
||||
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
|
||||
@rm -f .test1
|
||||
|
||||
else
|
||||
|
||||
test_x86:
|
||||
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ifeq "$(PYTHON_OK)" "1"
|
||||
|
||||
test_python:
|
||||
@rm -f .test 2> /dev/null
|
||||
@echo "[+] $(PYTHON_VERSION) support seems to be working."
|
||||
|
||||
else
|
||||
|
||||
test_python:
|
||||
@echo "[-] You seem to need to install the package python3-dev or python2-dev (and perhaps python[23]-apt), but it is optional so we continue"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile."
|
||||
|
||||
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
|
||||
|
||||
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
ln -sf afl-as as
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
radamsa: src/third_party/libradamsa/libradamsa.so
|
||||
cp src/third_party/libradamsa/libradamsa.so .
|
||||
|
||||
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
||||
$(MAKE) -C src/third_party/libradamsa/ CFLAGS="$(CFLAGS)"
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
document: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(AFL_FUZZ_FILES) -D_AFL_DOCUMENT_MUTATIONS src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(LDFLAGS) $(PYFLAGS)
|
||||
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 examples/*/*.c
|
||||
./.custom-format.py -i examples/*/*.h
|
||||
./.custom-format.py -i qemu_mode/patches/*.h
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.c
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.cc
|
||||
./.custom-format.py -i qemu_mode/libcompcov/*.h
|
||||
./.custom-format.py -i qbdi_mode/*.c
|
||||
./.custom-format.py -i qbdi_mode/*.cpp
|
||||
./.custom-format.py -i *.h
|
||||
./.custom-format.py -i *.c
|
||||
@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_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 )
|
||||
./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
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.md for a faster alternative to afl-gcc."; fi
|
||||
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
|
||||
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
|
||||
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
unit_clean:
|
||||
@gmake unit_clean
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.1.tar.xz afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast *.so *.8
|
||||
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
|
||||
-$(MAKE) -C llvm_mode clean
|
||||
-$(MAKE) -C gcc_plugin clean
|
||||
$(MAKE) -C libdislocator clean
|
||||
$(MAKE) -C libtokencap clean
|
||||
$(MAKE) -C examples/socket_fuzzing clean
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
$(MAKE) -C src/third_party/libradamsa/ clean
|
||||
-rm -rf unicorn_mode/unicornafl
|
||||
|
||||
distrib: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
binary-only: all radamsa
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
$(MAKE) -C examples/socket_fuzzing
|
||||
$(MAKE) -C examples/argv_fuzzing
|
||||
cd qemu_mode && sh ./build_qemu_support.sh
|
||||
cd unicorn_mode && sh ./build_unicorn_support.sh
|
||||
|
||||
source-only: all radamsa
|
||||
-$(MAKE) -C llvm_mode
|
||||
-$(MAKE) -C gcc_plugin
|
||||
$(MAKE) -C libdislocator
|
||||
$(MAKE) -C libtokencap
|
||||
|
||||
%.8: %
|
||||
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
|
||||
@echo .SH NAME >> $@
|
||||
@echo .B $* >> $@
|
||||
@echo >> $@
|
||||
@echo .SH SYNOPSIS >> $@
|
||||
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@
|
||||
@echo >> $@
|
||||
@echo .SH OPTIONS >> $@
|
||||
@echo .nf >> $@
|
||||
@./$* -h 2>&1 | tail -n +4 >> $@
|
||||
@echo >> $@
|
||||
@echo .SH AUTHOR >> $@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> $@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> $@
|
||||
@echo >> $@
|
||||
@echo .SH LICENSE >> $@
|
||||
@echo Apache License Version 2.0, January 2004 >> $@
|
||||
|
||||
install: all $(MANPAGES)
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
ifndef AFL_TRACE_PC
|
||||
if [ -f afl-clang-fast -a -f libLLVMInsTrim.so -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 libLLVMInsTrim.so afl-llvm-pass.so afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
else
|
||||
if [ -f afl-clang-fast -a -f afl-llvm-rt.o ]; then set -e; install -m 755 afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
endif
|
||||
if [ -f afl-llvm-rt-32.o ]; then set -e; install -m 755 afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-llvm-rt-64.o ]; then set -e; install -m 755 afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f compare-transform-pass.so ]; then set -e; install -m 755 compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-compares-pass.so ]; then set -e; install -m 755 split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f split-switches-pass.so ]; then set -e; install -m 755 split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f libradamsa.so ]; then set -e; install -m 755 libradamsa.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
|
||||
$(MAKE) -C examples/socket_fuzzing install
|
||||
$(MAKE) -C examples/argv_fuzzing install
|
||||
|
||||
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
|
||||
set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
|
||||
|
||||
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
|
||||
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
|
||||
|
||||
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
|
||||
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
|
||||
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
|
||||
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
|
||||
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
|
||||
|
||||
@gmake clean
|
||||
|
174
README.md
174
README.md
@ -2,17 +2,17 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
||||

|
||||

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

|
||||
|
||||
Release Version: 2.60c
|
||||
|
||||
Github Version: 2.60d
|
||||
|
||||
includes all necessary/interesting changes from Google's afl 2.56b
|
||||
|
||||
|
||||
Originally developed by Michal "lcamtuf" Zalewski.
|
||||
|
||||
Repository: [https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
|
||||
afl++ is maintained by Marc "van Hauser" Heuse <mh@mh-sec.de>,
|
||||
Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
|
||||
|
||||
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
|
||||
it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
|
||||
|
||||
|
||||
## The enhancements compared to the original stock afl
|
||||
|
||||
Many improvements were made over the official afl release - which did not
|
||||
get any feature improvements since November 2017.
|
||||
|
||||
Among other changes afl++ has a more performant llvm_mode, supports
|
||||
llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU,
|
||||
better *BSD and Android support and much, much more.
|
||||
|
||||
Additionally the following features and patches have been integrated:
|
||||
|
||||
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
|
||||
|
||||
* The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
|
||||
|
||||
* InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
|
||||
|
||||
* C. Holler's afl-fuzz Python mutator module and llvm_mode whitelist support: [https://github.com/choller/afl](https://github.com/choller/afl)
|
||||
|
||||
* Custom mutator by a library (instead of Python) by kyakdan
|
||||
|
||||
* unicorn_mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
|
||||
|
||||
* laf-intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
|
||||
|
||||
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
|
||||
|
||||
* Persistent mode and deferred forkserver for qemu_mode
|
||||
|
||||
* Win32 PE binary-only fuzzing with QEMU and Wine
|
||||
|
||||
* Radamsa mutator (enable with `-R` to add or `-RR` to run it exclusivly).
|
||||
|
||||
* qbdi_mode: fuzz android native libraries via QBDI framework
|
||||
|
||||
|
||||
A more thorough list is available in the PATCHES file.
|
||||
|
||||
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
|
||||
| ----------------------- |:-------:|:---------:|:----------:|:---------:|:------------:|
|
||||
| laf-intel / CompCov | | x | | x86/arm | x86/arm |
|
||||
| NeverZero | x | x(1) | (2) | x | x |
|
||||
| Persistent mode | | x | x | x86 | x |
|
||||
| Whitelist | | x | x | | |
|
||||
| InsTrim | | x | | | |
|
||||
|
||||
neverZero:
|
||||
|
||||
(1) only in LLVM >= 9.0 due to a bug in llvm in previous versions
|
||||
|
||||
(2) gcc creates non-performant code, hence it is disabled in gcc_plugin
|
||||
|
||||
So all in all this is the best-of afl that is currently out there :-)
|
||||
|
||||
For new versions and additional information, check out:
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
|
||||
To compare notes with other users or get notified about major new features,
|
||||
send a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to
|
||||
read this file.
|
||||
|
||||
|
||||
## 0) Building and installing afl++
|
||||
|
||||
afl++ has many build options.
|
||||
The easiest is to build and install everything:
|
||||
|
||||
```shell
|
||||
$ make distrib
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
|
||||
more. If you just want plain afl then do "make all", however compiling and
|
||||
using at least llvm_mode is highly recommended for much better results -
|
||||
hence in this case
|
||||
|
||||
```shell
|
||||
$ make source-only
|
||||
```
|
||||
is what you should choose.
|
||||
|
||||
These build options exist:
|
||||
|
||||
* all: just the main afl++ binaries
|
||||
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa
|
||||
* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap, radamsa
|
||||
* distrib: everything (for both binary-only and source code fuzzing)
|
||||
* install: installs everything you have compiled with the build options above
|
||||
* clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well
|
||||
* code-format: format the code, do this before you commit and send a PR please!
|
||||
* tests: runs test cases to ensure that all features are still working as they should
|
||||
* help: shows these build options
|
||||
|
||||
[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html) you can also build statically linked versions of the
|
||||
afl++ binaries by passing the STATIC=1 argument to make:
|
||||
|
||||
```shell
|
||||
$ make all STATIC=1
|
||||
```
|
||||
|
||||
Note that afl++ is faster and better the newer the compilers used are.
|
||||
Hence gcc-9 and especially llvm-9 should be the compilers of choice.
|
||||
If your distribution does not have them, you can use the Dockerfile:
|
||||
|
||||
```shell
|
||||
$ docker build -t aflplusplus
|
||||
```
|
||||
|
||||
|
||||
## 1) Challenges of guided fuzzing
|
||||
|
||||
Fuzzing is one of the most powerful and proven strategies for identifying
|
||||
security issues in real-world software; it is responsible for the vast
|
||||
majority of remote code execution and privilege escalation bugs found to date
|
||||
in security-critical software.
|
||||
|
||||
Unfortunately, fuzzing is also relatively shallow; blind, random mutations
|
||||
make it very unlikely to reach certain code paths in the tested code, leaving
|
||||
some vulnerabilities firmly outside the reach of this technique.
|
||||
|
||||
There have been numerous attempts to solve this problem. One of the early
|
||||
approaches - pioneered by Tavis Ormandy - is corpus distillation. The method
|
||||
relies on coverage signals to select a subset of interesting seeds from a
|
||||
massive, high-quality corpus of candidate files, and then fuzz them by
|
||||
traditional means. The approach works exceptionally well, but requires such
|
||||
a corpus to be readily available. In addition, block coverage measurements
|
||||
provide only a very simplistic understanding of program state, and are less
|
||||
useful for guiding the fuzzing effort in the long haul.
|
||||
|
||||
Other, more sophisticated research has focused on techniques such as program
|
||||
flow analysis ("concolic execution"), symbolic execution, or static analysis.
|
||||
All these methods are extremely promising in experimental settings, but tend
|
||||
to suffer from reliability and performance problems in practical uses - and
|
||||
currently do not offer a viable alternative to "dumb" fuzzing techniques.
|
||||
|
||||
|
||||
## 2) The afl-fuzz approach
|
||||
|
||||
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
|
||||
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
|
||||
form of edge coverage to effortlessly pick up subtle, local-scale changes to
|
||||
program control flow.
|
||||
|
||||
Simplifying a bit, the overall algorithm can be summed up as:
|
||||
|
||||
1) Load user-supplied initial test cases into the queue,
|
||||
|
||||
2) Take next input file from the queue,
|
||||
|
||||
3) Attempt to trim the test case to the smallest size that doesn't alter
|
||||
the measured behavior of the program,
|
||||
|
||||
4) Repeatedly mutate the file using a balanced and well-researched variety
|
||||
of traditional fuzzing strategies,
|
||||
|
||||
5) If any of the generated mutations resulted in a new state transition
|
||||
recorded by the instrumentation, add mutated output as a new entry in the
|
||||
queue.
|
||||
|
||||
6) Go to 2.
|
||||
|
||||
The discovered test cases are also periodically culled to eliminate ones that
|
||||
have been obsoleted by newer, higher-coverage finds; and undergo several other
|
||||
instrumentation-driven effort minimization steps.
|
||||
|
||||
As a side result of the fuzzing process, the tool creates a small,
|
||||
self-contained corpus of interesting test cases. These are extremely useful
|
||||
for seeding other, labor- or resource-intensive testing regimes - for example,
|
||||
for stress-testing browsers, office applications, graphics suites, or
|
||||
closed-source tools.
|
||||
|
||||
The fuzzer is thoroughly tested to deliver out-of-the-box performance far
|
||||
superior to blind fuzzing or coverage-only tools.
|
||||
|
||||
|
||||
## 3) Instrumenting programs for use with AFL
|
||||
|
||||
PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
|
||||
instead of afl-gcc/afl-g++ is much faster and has a few cool features.
|
||||
See llvm_mode/ - however few code does not compile with llvm.
|
||||
We support llvm versions 3.8.0 to 11.
|
||||
|
||||
When source code is available, instrumentation can be injected by a companion
|
||||
tool that works as a drop-in replacement for gcc or clang in any standard build
|
||||
process for third-party code.
|
||||
|
||||
The instrumentation has a fairly modest performance impact; in conjunction with
|
||||
other optimizations implemented by afl-fuzz, most programs can be fuzzed as fast
|
||||
or even faster than possible with traditional tools.
|
||||
|
||||
The correct way to recompile the target program may vary depending on the
|
||||
specifics of the build process, but a nearly-universal approach would be:
|
||||
|
||||
```shell
|
||||
$ CC=/path/to/afl/afl-gcc ./configure
|
||||
$ make clean all
|
||||
```
|
||||
|
||||
For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.
|
||||
|
||||
The clang wrappers (afl-clang and afl-clang++) can be used in the same way;
|
||||
clang users may also opt to leverage a higher-performance instrumentation mode,
|
||||
as described in [llvm_mode/README.md](llvm_mode/README.md).
|
||||
Clang/LLVM has a much better performance and works with LLVM version 3.8.0 to 11.
|
||||
|
||||
Using the LAF Intel performance enhancements are also recommended, see
|
||||
[llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md)
|
||||
|
||||
Using partial instrumentation is also recommended, see
|
||||
[llvm_mode/README.whitelist.md](llvm_mode/README.whitelist.md)
|
||||
|
||||
When testing libraries, you need to find or write a simple program that reads
|
||||
data from stdin or from a file and passes it to the tested library. In such a
|
||||
case, it is essential to link this executable against a static version of the
|
||||
instrumented library, or to make sure that the correct .so file is loaded at
|
||||
runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static
|
||||
build, usually possible via:
|
||||
|
||||
```shell
|
||||
$ CC=/path/to/afl/afl-gcc ./configure --disable-shared
|
||||
```
|
||||
|
||||
Setting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to
|
||||
automatically enable code hardening options that make it easier to detect
|
||||
simple memory bugs. Libdislocator, a helper library included with AFL (see
|
||||
[libdislocator/README.md](libdislocator/README.md)) can help uncover heap corruption issues, too.
|
||||
|
||||
PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md)
|
||||
file for important caveats.
|
||||
|
||||
|
||||
## 4) Instrumenting binary-only apps
|
||||
|
||||
When source code is *NOT* available, the fuzzer offers experimental support for
|
||||
fast, on-the-fly instrumentation of black-box binaries. This is accomplished
|
||||
with a version of QEMU running in the lesser-known "user space emulation" mode.
|
||||
|
||||
QEMU is a project separate from AFL, but you can conveniently build the
|
||||
feature by doing:
|
||||
|
||||
```shell
|
||||
$ cd qemu_mode
|
||||
$ ./build_qemu_support.sh
|
||||
```
|
||||
|
||||
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
|
||||
|
||||
The mode is approximately 2-5x slower than compile-time instrumentation, is
|
||||
less conducive to parallelization, and may have some other quirks.
|
||||
|
||||
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
|
||||
your binary, then you can use afl-fuzz normally and it will have twice
|
||||
the speed compared to qemu_mode.
|
||||
|
||||
A more comprehensive description of these and other options can be found in
|
||||
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
|
||||
|
||||
|
||||
## 5) Power schedules
|
||||
|
||||
The power schedules were copied from Marcel Böhme's excellent AFLfast
|
||||
implementation and expand on the ability to discover new paths and
|
||||
therefore may increase the code coverage.
|
||||
|
||||
The available schedules are:
|
||||
|
||||
- explore (default)
|
||||
- fast
|
||||
- coe
|
||||
- quad
|
||||
- lin
|
||||
- exploit
|
||||
|
||||
In parallel mode (-M/-S, several instances with shared queue), we suggest to
|
||||
run the master using the exploit schedule (-p exploit) and the slaves with a
|
||||
combination of cut-off-exponential (-p coe), exponential (-p fast; default),
|
||||
and explore (-p explore) schedules.
|
||||
|
||||
In single mode, using -p fast is usually more beneficial than the default
|
||||
explore mode.
|
||||
(We don't want to change the default behaviour of afl, so "fast" has not been
|
||||
made the default mode).
|
||||
|
||||
More details can be found in the paper published at the 23rd ACM Conference on
|
||||
Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
|
||||
## 6) Choosing initial test cases
|
||||
|
||||
To operate correctly, the fuzzer requires one or more starting file that
|
||||
contains a good example of the input data normally expected by the targeted
|
||||
application. There are two basic rules:
|
||||
|
||||
- Keep the files small. Under 1 kB is ideal, although not strictly necessary.
|
||||
For a discussion of why size matters, see [perf_tips.md](docs/perf_tips.md).
|
||||
|
||||
- Use multiple test cases only if they are functionally different from
|
||||
each other. There is no point in using fifty different vacation photos
|
||||
to fuzz an image library.
|
||||
|
||||
You can find many good examples of starting files in the testcases/ subdirectory
|
||||
that comes with this tool.
|
||||
|
||||
PS. If a large corpus of data is available for screening, you may want to use
|
||||
the afl-cmin utility to identify a subset of functionally distinct files that
|
||||
exercise different code paths in the target binary.
|
||||
|
||||
|
||||
## 7) Fuzzing binaries
|
||||
|
||||
The fuzzing process itself is carried out by the afl-fuzz utility. This program
|
||||
requires a read-only directory with initial test cases, a separate place to
|
||||
store its findings, plus a path to the binary to test.
|
||||
|
||||
For target binaries that accept input directly from stdin, the usual syntax is:
|
||||
|
||||
```shell
|
||||
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
|
||||
```
|
||||
|
||||
For programs that take input from a file, use '@@' to mark the location in
|
||||
the target's command line where the input file name should be placed. The
|
||||
fuzzer will substitute this for you:
|
||||
|
||||
```shell
|
||||
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
|
||||
```
|
||||
|
||||
You can also use the -f option to have the mutated data written to a specific
|
||||
file. This is useful if the program expects a particular file extension or so.
|
||||
|
||||
Non-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command
|
||||
line) or in a traditional, blind-fuzzer mode (specify -n).
|
||||
|
||||
You can use -t and -m to override the default timeout and memory limit for the
|
||||
executed process; rare examples of targets that may need these settings touched
|
||||
include compilers and video decoders.
|
||||
|
||||
Tips for optimizing fuzzing performance are discussed in [perf_tips.md](docs/perf_tips.md).
|
||||
|
||||
Note that afl-fuzz starts by performing an array of deterministic fuzzing
|
||||
steps, which can take several days, but tend to produce neat test cases. If you
|
||||
want quick & dirty results right away - akin to zzuf and other traditional
|
||||
fuzzers - add the -d option to the command line.
|
||||
|
||||
|
||||
## 8) Interpreting output
|
||||
|
||||
See the [docs/status_screen.md](docs/status_screen.md) file for information on
|
||||
how to interpret the displayed stats and monitor the health of the process. Be
|
||||
sure to consult this file especially if any UI elements are highlighted in red.
|
||||
|
||||
The fuzzing process will continue until you press Ctrl-C. At minimum, you want
|
||||
to allow the fuzzer to complete one queue cycle, which may take anywhere from a
|
||||
couple of hours to a week or so.
|
||||
|
||||
There are three subdirectories created within the output directory and updated
|
||||
in real time:
|
||||
|
||||
- queue/ - test cases for every distinctive execution path, plus all the
|
||||
starting files given by the user. This is the synthesized corpus
|
||||
mentioned in section 2.
|
||||
|
||||
Before using this corpus for any other purposes, you can shrink
|
||||
it to a smaller size using the afl-cmin tool. The tool will find
|
||||
a smaller subset of files offering equivalent edge coverage.
|
||||
|
||||
- crashes/ - unique test cases that cause the tested program to receive a
|
||||
fatal signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are
|
||||
grouped by the received signal.
|
||||
|
||||
- hangs/ - unique test cases that cause the tested program to time out. The
|
||||
default time limit before something is classified as a hang is
|
||||
the larger of 1 second and the value of the -t parameter.
|
||||
The value can be fine-tuned by setting AFL_HANG_TMOUT, but this
|
||||
is rarely necessary.
|
||||
|
||||
Crashes and hangs are considered "unique" if the associated execution paths
|
||||
involve any state transitions not seen in previously-recorded faults. If a
|
||||
single bug can be reached in multiple ways, there will be some count inflation
|
||||
early in the process, but this should quickly taper off.
|
||||
|
||||
The file names for crashes and hangs are correlated with parent, non-faulting
|
||||
queue entries. This should help with debugging.
|
||||
|
||||
When you can't reproduce a crash found by afl-fuzz, the most likely cause is
|
||||
that you are not setting the same memory limit as used by the tool. Try:
|
||||
|
||||
```shell
|
||||
$ LIMIT_MB=50
|
||||
$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )
|
||||
```
|
||||
|
||||
Change LIMIT_MB to match the -m parameter passed to afl-fuzz. On OpenBSD,
|
||||
also change -Sv to -Sd.
|
||||
|
||||
Any existing output directory can be also used to resume aborted jobs; try:
|
||||
|
||||
```shell
|
||||
$ ./afl-fuzz -i- -o existing_output_dir [...etc...]
|
||||
```
|
||||
|
||||
If you have gnuplot installed, you can also generate some pretty graphs for any
|
||||
active fuzzing task using afl-plot. For an example of how this looks like,
|
||||
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
|
||||
|
||||
|
||||
## 9) Parallelized fuzzing
|
||||
|
||||
Every instance of afl-fuzz takes up roughly one core. This means that on
|
||||
multi-core systems, parallelization is necessary to fully utilize the hardware.
|
||||
For tips on how to fuzz a common target on multiple cores or multiple networked
|
||||
machines, please refer to [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md).
|
||||
|
||||
The parallel fuzzing mode also offers a simple way for interfacing AFL to other
|
||||
fuzzers, to symbolic or concolic execution engines, and so forth; again, see the
|
||||
last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips.
|
||||
|
||||
|
||||
## 10) Fuzzer dictionaries
|
||||
|
||||
By default, afl-fuzz mutation engine is optimized for compact data formats -
|
||||
say, images, multimedia, compressed data, regular expression syntax, or shell
|
||||
scripts. It is somewhat less suited for languages with particularly verbose and
|
||||
redundant verbiage - notably including HTML, SQL, or JavaScript.
|
||||
|
||||
To avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to
|
||||
seed the fuzzing process with an optional dictionary of language keywords,
|
||||
magic headers, or other special tokens associated with the targeted data type
|
||||
-- and use that to reconstruct the underlying grammar on the go:
|
||||
|
||||
[http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)
|
||||
|
||||
To use this feature, you first need to create a dictionary in one of the two
|
||||
formats discussed in [dictionaries/README.md](dictionaries/README.md);
|
||||
and then point the fuzzer to it via the -x option in the command line.
|
||||
|
||||
(Several common dictionaries are already provided in that subdirectory, too.)
|
||||
|
||||
There is no way to provide more structured descriptions of the underlying
|
||||
syntax, but the fuzzer will likely figure out some of this based on the
|
||||
instrumentation feedback alone. This actually works in practice, say:
|
||||
|
||||
[http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)
|
||||
|
||||
PS. Even when no explicit dictionary is given, afl-fuzz will try to extract
|
||||
existing syntax tokens in the input corpus by watching the instrumentation
|
||||
very closely during deterministic byte flips. This works for some types of
|
||||
parsers and grammars, but isn't nearly as good as the -x mode.
|
||||
|
||||
If a dictionary is really hard to come by, another option is to let AFL run
|
||||
for a while, and then use the token capture library that comes as a companion
|
||||
utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md).
|
||||
|
||||
|
||||
## 11) Crash triage
|
||||
|
||||
The coverage-based grouping of crashes usually produces a small data set that
|
||||
can be quickly triaged manually or with a very simple GDB or Valgrind script.
|
||||
Every crash is also traceable to its parent non-crashing test case in the
|
||||
queue, making it easier to diagnose faults.
|
||||
|
||||
Having said that, it's important to acknowledge that some fuzzing crashes can be
|
||||
difficult to quickly evaluate for exploitability without a lot of debugging and
|
||||
code analysis work. To assist with this task, afl-fuzz supports a very unique
|
||||
"crash exploration" mode enabled with the -C flag.
|
||||
|
||||
In this mode, the fuzzer takes one or more crashing test cases as the input,
|
||||
and uses its feedback-driven fuzzing strategies to very quickly enumerate all
|
||||
code paths that can be reached in the program while keeping it in the
|
||||
crashing state.
|
||||
|
||||
Mutations that do not result in a crash are rejected; so are any changes that
|
||||
do not affect the execution path.
|
||||
|
||||
The output is a small corpus of files that can be very rapidly examined to see
|
||||
what degree of control the attacker has over the faulting address, or whether
|
||||
it is possible to get past an initial out-of-bounds read - and see what lies
|
||||
beneath.
|
||||
|
||||
Oh, one more thing: for test case minimization, give afl-tmin a try. The tool
|
||||
can be operated in a very simple way:
|
||||
|
||||
```shell
|
||||
$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
|
||||
```
|
||||
|
||||
The tool works with crashing and non-crashing test cases alike. In the crash
|
||||
mode, it will happily accept instrumented and non-instrumented binaries. In the
|
||||
non-crashing mode, the minimizer relies on standard AFL instrumentation to make
|
||||
the file simpler without altering the execution path.
|
||||
|
||||
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
|
||||
afl-fuzz.
|
||||
|
||||
Another recent addition to AFL is the afl-analyze tool. It takes an input
|
||||
file, attempts to sequentially flip bytes, and observes the behavior of the
|
||||
tested program. It then color-codes the input based on which sections appear to
|
||||
be critical, and which are not; while not bulletproof, it can often offer quick
|
||||
insights into complex file formats. More info about its operation can be found
|
||||
near the end of [docs/technical_details.md](docs/technical_details.md).
|
||||
|
||||
|
||||
## 12) Going beyond crashes
|
||||
|
||||
Fuzzing is a wonderful and underutilized technique for discovering non-crashing
|
||||
design and implementation errors, too. Quite a few interesting bugs have been
|
||||
found by modifying the target programs to call abort() when, say:
|
||||
|
||||
- Two bignum libraries produce different outputs when given the same
|
||||
fuzzer-generated input,
|
||||
|
||||
- An image library produces different outputs when asked to decode the same
|
||||
input image several times in a row,
|
||||
|
||||
- A serialization / deserialization library fails to produce stable outputs
|
||||
when iteratively serializing and deserializing fuzzer-supplied data,
|
||||
|
||||
- A compression library produces an output inconsistent with the input file
|
||||
when asked to compress and then decompress a particular blob.
|
||||
|
||||
Implementing these or similar sanity checks usually takes very little time;
|
||||
if you are the maintainer of a particular package, you can make this code
|
||||
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
|
||||
shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).
|
||||
|
||||
|
||||
## 13) Common-sense risks
|
||||
|
||||
Please keep in mind that, similarly to many other computationally-intensive
|
||||
tasks, fuzzing may put strain on your hardware and on the OS. In particular:
|
||||
|
||||
- Your CPU will run hot and will need adequate cooling. In most cases, if
|
||||
cooling is insufficient or stops working properly, CPU speeds will be
|
||||
automatically throttled. That said, especially when fuzzing on less
|
||||
suitable hardware (laptops, smartphones, etc), it's not entirely impossible
|
||||
for something to blow up.
|
||||
|
||||
- Targeted programs may end up erratically grabbing gigabytes of memory or
|
||||
filling up disk space with junk files. AFL tries to enforce basic memory
|
||||
limits, but can't prevent each and every possible mishap. The bottom line
|
||||
is that you shouldn't be fuzzing on systems where the prospect of data loss
|
||||
is not an acceptable risk.
|
||||
|
||||
- Fuzzing involves billions of reads and writes to the filesystem. On modern
|
||||
systems, this will be usually heavily cached, resulting in fairly modest
|
||||
"physical" I/O - but there are many factors that may alter this equation.
|
||||
It is your responsibility to monitor for potential trouble; with very heavy
|
||||
I/O, the lifespan of many HDDs and SSDs may be reduced.
|
||||
|
||||
A good way to monitor disk I/O on Linux is the 'iostat' command:
|
||||
|
||||
```shell
|
||||
$ iostat -d 3 -x -k [...optional disk ID...]
|
||||
```
|
||||
|
||||
|
||||
## 14) Known limitations & areas for improvement
|
||||
|
||||
Here are some of the most important caveats for AFL:
|
||||
|
||||
- AFL detects faults by checking for the first spawned process dying due to
|
||||
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
|
||||
these signals may need to have the relevant code commented out. In the same
|
||||
vein, faults in child processed spawned by the fuzzed target may evade
|
||||
detection unless you manually add some code to catch that.
|
||||
|
||||
- As with any other brute-force tool, the fuzzer offers limited coverage if
|
||||
encryption, checksums, cryptographic signatures, or compression are used to
|
||||
wholly wrap the actual data format to be tested.
|
||||
|
||||
To work around this, you can comment out the relevant checks (see
|
||||
examples/libpng_no_checksum/ for inspiration); if this is not possible,
|
||||
you can also write a postprocessor, as explained in
|
||||
examples/post_library/ (with AFL_POST_LIBRARY)
|
||||
|
||||
- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
|
||||
isn't due to any specific fault of afl-fuzz; see [docs/notes_for_asan.md](docs/notes_for_asan.md)
|
||||
for tips.
|
||||
|
||||
- There is no direct support for fuzzing network services, background
|
||||
daemons, or interactive apps that require UI interaction to work. You may
|
||||
need to make simple code changes to make them behave in a more traditional
|
||||
way. Preeny may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
|
||||
- AFL doesn't output human-readable coverage data. If you want to monitor
|
||||
coverage, use afl-cov from Michael Rash: [https://github.com/mrash/afl-cov](https://github.com/mrash/afl-cov)
|
||||
|
||||
- Occasionally, sentient machines rise against their creators. If this
|
||||
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
|
||||
|
||||
Beyond this, see INSTALL for platform-specific tips.
|
||||
|
||||
|
||||
## 15) Special thanks
|
||||
|
||||
Many of the improvements to the original afl and afl++ wouldn't be possible
|
||||
without feedback, bug reports, or patches from:
|
||||
|
||||
```
|
||||
Jann Horn Hanno Boeck
|
||||
Felix Groebert Jakub Wilk
|
||||
Richard W. M. Jones Alexander Cherepanov
|
||||
Tom Ritter Hovik Manucharyan
|
||||
Sebastian Roschke Eberhard Mattes
|
||||
Padraig Brady Ben Laurie
|
||||
@dronesec Luca Barbato
|
||||
Tobias Ospelt Thomas Jarosch
|
||||
Martin Carpenter Mudge Zatko
|
||||
Joe Zbiciak Ryan Govostes
|
||||
Michael Rash William Robinet
|
||||
Jonathan Gray Filipe Cabecinhas
|
||||
Nico Weber Jodie Cunningham
|
||||
Andrew Griffiths Parker Thompson
|
||||
Jonathan Neuschaefer Tyler Nighswander
|
||||
Ben Nagy Samir Aguiar
|
||||
Aidan Thornton Aleksandar Nikolich
|
||||
Sam Hakim Laszlo Szekeres
|
||||
David A. Wheeler Turo Lamminen
|
||||
Andreas Stieger Richard Godbee
|
||||
Louis Dassy teor2345
|
||||
Alex Moneger Dmitry Vyukov
|
||||
Keegan McAllister Kostya Serebryany
|
||||
Richo Healey Martijn Bogaard
|
||||
rc0r Jonathan Foote
|
||||
Christian Holler Dominique Pelle
|
||||
Jacek Wielemborek Leo Barnes
|
||||
Jeremy Barnes Jeff Trull
|
||||
Guillaume Endignoux ilovezfs
|
||||
Daniel Godas-Lopez Franjo Ivancic
|
||||
Austin Seipp Daniel Komaromy
|
||||
Daniel Binderman Jonathan Metzman
|
||||
Vegard Nossum Jan Kneschke
|
||||
Kurt Roeckx Marcel Boehme
|
||||
Van-Thuan Pham Abhik Roychoudhury
|
||||
Joshua J. Drake Toby Hutton
|
||||
Rene Freingruber Sergey Davidoff
|
||||
Sami Liedes Craig Young
|
||||
Andrzej Jackowski Daniel Hodson
|
||||
Nathan Voss Dominik Maier
|
||||
Andrea Biondo Vincent Le Garrec
|
||||
Khaled Yakdan Kuang-che Wu
|
||||
```
|
||||
|
||||
Thank you!
|
||||
|
||||
|
||||
## 16) Contact
|
||||
|
||||
Questions? Concerns? Bug reports? The contributors can be reached via
|
||||
[https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus)
|
||||
|
||||
There is also a mailing list for the afl project; to join, send a mail to
|
||||
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse
|
||||
archives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users)
|
1
docs/README.md
Symbolic link
1
docs/README.md
Symbolic link
@ -0,0 +1 @@
|
||||
../README.md
|
@ -148,7 +148,7 @@
|
||||
There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer)
|
||||
|
||||
There is also an early implementation in an AFL++ test branch:
|
||||
[https://github.com/vanhauser-thc/AFLplusplus/tree/frida](https://github.com/vanhauser-thc/AFLplusplus/tree/frida)
|
||||
[https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida)
|
||||
|
||||
|
||||
## PIN & DYNAMORIO
|
||||
|
@ -1,36 +0,0 @@
|
||||
# Adding custom mutators to AFL
|
||||
|
||||
This file describes how you can implement custom mutations to be used in AFL.
|
||||
|
||||
Implemented by Khaled Yakdan from Code Intelligence <yakdan@code-intelligence.de>
|
||||
|
||||
## 1) Description
|
||||
|
||||
Custom mutator libraries can be passed to afl-fuzz to perform custom mutations
|
||||
on test cases beyond those available in AFL - for example, to enable structure-aware
|
||||
fuzzing by using libraries that perform mutations according to a given grammar.
|
||||
|
||||
The custom mutator library is passed to afl-fuzz via the AFL_CUSTOM_MUTATOR_LIBRARY
|
||||
environment variable. The library must export the afl_custom_mutator() function and
|
||||
must be compiled as a shared object. For example:
|
||||
$CC -shared -Wall -O3 <lib-name>.c -o <lib-name>.so
|
||||
|
||||
Note: unless AFL_CUSTOM_MUTATOR_ONLY is set, its state mutator like any others,
|
||||
so it will be used for some test cases, and other mutators for others.
|
||||
|
||||
Only if AFL_CUSTOM_MUTATOR_ONLY is set the afl_custom_mutator() function will
|
||||
be called every time it needs to mutate test case!
|
||||
|
||||
For some cases, the format of the mutated data returned from
|
||||
the custom mutator is not suitable to directly execute the target with this input.
|
||||
For example, when using libprotobuf-mutator, the data returned is in a protobuf
|
||||
format which corresponds to a given grammar. In order to execute the target,
|
||||
the protobuf data must be converted to the plain-text format expected by the target.
|
||||
In such scenarios, the user can define the afl_pre_save_handler() function. This function
|
||||
is then transforms the data into the format expected by the API before executing the target.
|
||||
afl_pre_save_handler is optional and does not have to be implemented if its functionality
|
||||
is not needed.
|
||||
|
||||
## 2) Example
|
||||
|
||||
A simple example is provided in ../examples/custom_mutators/
|
255
docs/custom_mutators.md
Normal file
255
docs/custom_mutators.md
Normal file
@ -0,0 +1,255 @@
|
||||
# Custom Mutators in AFL++
|
||||
|
||||
This file describes how you can implement custom mutations to be used in AFL.
|
||||
For now, we support C/C++ library and Python module, collectivelly named as the
|
||||
custom mutator.
|
||||
|
||||
Implemented by
|
||||
- C/C++ library (`*.so`): Khaled Yakdan from Code Intelligence (<yakdan@code-intelligence.de>)
|
||||
- Python module: Christian Holler from Mozilla (<choller@mozilla.com>)
|
||||
|
||||
## 1) Introduction
|
||||
|
||||
Custom mutators can be passed to `afl-fuzz` to perform custom mutations on test
|
||||
cases beyond those available in AFL. For example, to enable structure-aware
|
||||
fuzzing by using libraries that perform mutations according to a given grammar.
|
||||
|
||||
The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY`
|
||||
or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function.
|
||||
Now afl also supports multiple custom mutators which can be specified in the same `AFL_CUSTOM_MUTATOR_LIBRARY` environment variable like this.
|
||||
```bash
|
||||
export AFL_CUSTOM_MUTATOR_LIBRARY="full/path/to/mutator_first.so;full/path/to/mutator_second.so"
|
||||
```
|
||||
Please see [APIs](#2-apis) and [Usage](#3-usage) for detail.
|
||||
|
||||
The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage).
|
||||
|
||||
Note: If `AFL_CUSTOM_MUTATOR_ONLY` is set, all mutations will solely be
|
||||
performed with the custom mutator.
|
||||
|
||||
## 2) APIs
|
||||
|
||||
C/C++:
|
||||
```c
|
||||
void *afl_custom_init(afl_t *afl, unsigned int seed);
|
||||
size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size);
|
||||
size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf);
|
||||
int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size);
|
||||
size_t afl_custom_trim(void *data, uint8_t **out_buf);
|
||||
int32_t afl_custom_post_trim(void *data, int success) {
|
||||
size_t afl_custom_havoc_mutation(void *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t max_size);
|
||||
uint8_t afl_custom_havoc_mutation_probability(void *data);
|
||||
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename);
|
||||
void afl_custom_queue_new_entry(void *data, const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue);
|
||||
void afl_custom_deinit(void *data);
|
||||
```
|
||||
|
||||
Python:
|
||||
```python
|
||||
def init(seed):
|
||||
pass
|
||||
|
||||
def fuzz(buf, add_buf, max_size):
|
||||
return mutated_out
|
||||
|
||||
def post_process(buf):
|
||||
return out_buf
|
||||
|
||||
def init_trim(buf):
|
||||
return cnt
|
||||
|
||||
def trim():
|
||||
return out_buf
|
||||
|
||||
def post_trim(success):
|
||||
return next_index
|
||||
|
||||
def havoc_mutation(buf, max_size):
|
||||
return mutated_out
|
||||
|
||||
def havoc_mutation_probability():
|
||||
return probability # int in [0, 100]
|
||||
|
||||
def queue_get(filename):
|
||||
return True
|
||||
|
||||
def queue_new_entry(filename_new_queue, filename_orig_queue):
|
||||
pass
|
||||
```
|
||||
|
||||
### Custom Mutation
|
||||
|
||||
- `init`:
|
||||
|
||||
This method is called when AFL++ starts up and is used to seed RNG and set up buffers and state.
|
||||
|
||||
- `queue_get` (optional):
|
||||
|
||||
This method determines whether the custom fuzzer should fuzz the current
|
||||
queue entry or not
|
||||
|
||||
- `fuzz` (optional):
|
||||
|
||||
This method performs custom mutations on a given input. It also accepts an
|
||||
additional test case.
|
||||
Note that this function is optional - but it makes sense to use it.
|
||||
You would only skip this if `post_process` is used to fix checksums etc.
|
||||
so you are using it e.g. as a post processing library.
|
||||
|
||||
- `havoc_mutation` and `havoc_mutation_probability` (optional):
|
||||
|
||||
`havoc_mutation` performs a single custom mutation on a given input. This
|
||||
mutation is stacked with the other mutations in havoc. The other method,
|
||||
`havoc_mutation_probability`, returns the probability that `havoc_mutation`
|
||||
is called in havoc. By default, it is 6%.
|
||||
|
||||
- `post_process` (optional):
|
||||
|
||||
For some cases, the format of the mutated data returned from the custom
|
||||
mutator is not suitable to directly execute the target with this input.
|
||||
For example, when using libprotobuf-mutator, the data returned is in a
|
||||
protobuf format which corresponds to a given grammar. In order to execute
|
||||
the target, the protobuf data must be converted to the plain-text format
|
||||
expected by the target. In such scenarios, the user can define the
|
||||
`post_process` function. This function is then transforming the data into the
|
||||
format expected by the API before executing the target.
|
||||
|
||||
- `queue_new_entry` (optional):
|
||||
|
||||
This methods is called after adding a new test case to the queue.
|
||||
|
||||
- `deinit`:
|
||||
|
||||
The last method to be called, deinitializing the state.
|
||||
|
||||
Note that there are also three functions for trimming as described in the
|
||||
next section.
|
||||
|
||||
### Trimming Support
|
||||
|
||||
The generic trimming routines implemented in AFL++ can easily destroy the
|
||||
structure of complex formats, possibly leading to a point where you have a lot
|
||||
of test cases in the queue that your Python module cannot process anymore but
|
||||
your target application still accepts. This is especially the case when your
|
||||
target can process a part of the input (causing coverage) and then errors out
|
||||
on the remaining input.
|
||||
|
||||
In such cases, it makes sense to implement a custom trimming routine. The API
|
||||
consists of multiple methods because after each trimming step, we have to go
|
||||
back into the C code to check if the coverage bitmap is still the same for the
|
||||
trimmed input. Here's a quick API description:
|
||||
|
||||
- `init_trim` (optional):
|
||||
|
||||
This method is called at the start of each trimming operation and receives
|
||||
the initial buffer. It should return the amount of iteration steps possible
|
||||
on this input (e.g. if your input has n elements and you want to remove them
|
||||
one by one, return n, if you do a binary search, return log(n), and so on).
|
||||
|
||||
If your trimming algorithm doesn't allow you to determine the amount of
|
||||
(remaining) steps easily (esp. while running), then you can alternatively
|
||||
return 1 here and always return 0 in `post_trim` until you are finished and
|
||||
no steps remain. In that case, returning 1 in `post_trim` will end the
|
||||
trimming routine. The whole current index/max iterations stuff is only used
|
||||
to show progress.
|
||||
|
||||
- `trim` (optional)
|
||||
|
||||
This method is called for each trimming operation. It doesn't have any
|
||||
arguments because we already have the initial buffer from `init_trim` and we
|
||||
can memorize the current state in the data variables. This can also save
|
||||
reparsing steps for each iteration. It should return the trimmed input
|
||||
buffer, where the returned data must not exceed the initial input data in
|
||||
length. Returning anything that is larger than the original data (passed to
|
||||
`init_trim`) will result in a fatal abort of AFL++.
|
||||
|
||||
- `post_trim` (optional)
|
||||
|
||||
This method is called after each trim operation to inform you if your
|
||||
trimming step was successful or not (in terms of coverage). If you receive
|
||||
a failure here, you should reset your input to the last known good state.
|
||||
In any case, this method must return the next trim iteration index (from 0
|
||||
to the maximum amount of steps you returned in `init_trim`).
|
||||
|
||||
Omitting any of three trimming methods will cause the trimming to be disabled
|
||||
and trigger a fallback to the builtin default trimming routine.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Optionally, the following environment variables are supported:
|
||||
|
||||
- `AFL_CUSTOM_MUTATOR_ONLY`
|
||||
|
||||
Disable all other mutation stages. This can prevent broken testcases
|
||||
(those that your Python module can't work with anymore) to fill up your
|
||||
queue. Best combined with a custom trimming routine (see below) because
|
||||
trimming can cause the same test breakage like havoc and splice.
|
||||
|
||||
|
||||
- `AFL_PYTHON_ONLY`
|
||||
|
||||
Deprecated and removed, use `AFL_CUSTOM_MUTATOR_ONLY` instead
|
||||
trimming can cause the same test breakage like havoc and splice.
|
||||
|
||||
- `AFL_DEBUG`
|
||||
|
||||
When combined with `AFL_NO_UI`, this causes the C trimming code to emit additional messages about the performance and actions of your custom trimmer. Use this to see if it works :)
|
||||
|
||||
## 3) Usage
|
||||
|
||||
### Prerequisite
|
||||
|
||||
For Python mutator, the python 3 or 2 development package is required. On
|
||||
Debian/Ubuntu/Kali this can be done:
|
||||
|
||||
```bash
|
||||
sudo apt install python3-dev
|
||||
# or
|
||||
sudo apt install python-dev
|
||||
```
|
||||
|
||||
Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects
|
||||
Python 2 and 3 through `python-config` if it is in the PATH and compiles
|
||||
`afl-fuzz` with the feature if available.
|
||||
|
||||
Note: for some distributions, you might also need the package `python[23]-apt`.
|
||||
In case your setup is different, set the necessary variables like this:
|
||||
`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
|
||||
|
||||
### Custom Mutator Preparation
|
||||
|
||||
For C/C++ mutator, the source code must be compiled as a shared object:
|
||||
```bash
|
||||
gcc -shared -Wall -O3 example.c -o example.so
|
||||
```
|
||||
Note that if you specify multiple custom mutators, the corresponding functions will
|
||||
be called in the order in which they are specified. e.g first `post_process` function of
|
||||
`example_first.so` will be called and then that of `example_second.so`
|
||||
|
||||
### Run
|
||||
|
||||
C/C++
|
||||
```bash
|
||||
export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so"
|
||||
afl-fuzz /path/to/program
|
||||
```
|
||||
|
||||
Python
|
||||
```bash
|
||||
export PYTHONPATH=`dirname /full/path/to/example.py`
|
||||
export AFL_PYTHON_MODULE=example
|
||||
afl-fuzz /path/to/program
|
||||
```
|
||||
|
||||
## 4) Example
|
||||
|
||||
Please see [example.c](../examples/custom_mutators/example.c) and
|
||||
[example.py](../examples/custom_mutators/example.py)
|
||||
|
||||
## 5) Other Resources
|
||||
|
||||
- AFL libprotobuf mutator
|
||||
- [bruce30262/libprotobuf-mutator_fuzzing_learning](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
|
||||
- [thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
|
||||
- [XML Fuzzing@NullCon 2017](https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf)
|
||||
- [A bug detected by AFL + XML-aware mutators](https://bugs.chromium.org/p/chromium/issues/detail?id=930663)
|
@ -31,7 +31,9 @@ tools make fairly broad use of environmental variables:
|
||||
|
||||
(You can also enable MSAN via AFL_USE_MSAN; ASAN and MSAN come with the
|
||||
same gotchas; the modes are mutually exclusive. UBSAN can be enabled
|
||||
similarly by setting the environment variable AFL_USE_UBSAN=1)
|
||||
similarly by setting the environment variable AFL_USE_UBSAN=1. Finally
|
||||
there is the Control Flow Integrity sanitizer that can be activated by
|
||||
AFL_USE_CFISAN=1)
|
||||
|
||||
- Setting AFL_CC, AFL_CXX, and AFL_AS lets you use alternate downstream
|
||||
compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
|
||||
@ -81,6 +83,10 @@ tools make fairly broad use of environmental variables:
|
||||
The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset
|
||||
of the settings discussed in section #1, with the exception of:
|
||||
|
||||
- Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting
|
||||
functions with a single basic block. This is useful for most C and
|
||||
some C++ targets. This works for all instrumentation modes.
|
||||
|
||||
- AFL_AS, since this toolchain does not directly invoke GNU as.
|
||||
|
||||
- TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are
|
||||
@ -91,6 +97,93 @@ of the settings discussed in section #1, with the exception of:
|
||||
|
||||
Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
### Select the instrumentation mode
|
||||
|
||||
- AFL_LLVM_INSTRUMENT - this configures the instrumentation mode.
|
||||
Available options:
|
||||
CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
|
||||
CFG - InsTrim instrumentation (see below)
|
||||
LTO - LTO instrumentation (see below)
|
||||
CTX - context sensitive instrumentation (see below)
|
||||
NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
|
||||
In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
|
||||
NGRAM, seperate the options with a comma "," then, e.g.:
|
||||
AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4
|
||||
Not that this is a good idea to use both CTX and NGRAM :)
|
||||
|
||||
### LTO
|
||||
|
||||
This is a different kind way of instrumentation: first it compiles all
|
||||
code in LTO (link time optimization) and then performs an edge inserting
|
||||
instrumentation which is 100% collision free (collisions are a big issue
|
||||
in afl and afl-like instrumentations). This is performed by using
|
||||
afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only
|
||||
built if LLVM 11 or newer is used.
|
||||
|
||||
- AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
|
||||
(recommended)
|
||||
|
||||
- AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target
|
||||
binary based on string compare and memory compare functions.
|
||||
afl-fuzz will automatically get these transmitted when starting to
|
||||
fuzz.
|
||||
|
||||
None of the following options are necessary to be used and are rather for
|
||||
manual use (which only ever the author of this LTO implementation will use).
|
||||
These are used if several seperated instrumentation are performed which
|
||||
are then later combined.
|
||||
|
||||
- AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than
|
||||
the default 0x10000. A value of 0 or empty sets the map address to be
|
||||
dynamic (the original afl way, which is slower)
|
||||
- AFL_LLVM_MAP_DYNAMIC sets the shared memory address to be dynamic
|
||||
- AFL_LLVM_LTO_STARTID sets the starting location ID for the instrumentation.
|
||||
This defaults to 1
|
||||
- AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written
|
||||
into the instrumentation is set in a global variable
|
||||
|
||||
See llvm_mode/README.LTO.md for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
This feature increases the speed by ~15% without any disadvantages to the
|
||||
classic instrumentation.
|
||||
|
||||
Note that there is also an LTO version (if you have llvm 11 or higher) -
|
||||
that is the best instrumentation we have. Use `afl-clang-lto` to activate.
|
||||
The InsTrim LTO version additionally has all the options and features of
|
||||
LTO (see above).
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM_LOOPHEAD=1 expands on INSTRIM to optimize loops.
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
See llvm_mode/README.instrim.md
|
||||
|
||||
### NGRAM
|
||||
|
||||
- Setting AFL_LLVM_NGRAM_SIZE or AFL_LLVM_INSTRUMENT=NGRAM-{value}
|
||||
activates ngram prev_loc coverage, good values are 2, 4 or 8
|
||||
(any value between 2 and 16 is valid).
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ctx.md
|
||||
|
||||
### CTX
|
||||
|
||||
- Setting AFL_LLVM_CTX or AFL_LLVM_INSTRUMENT=CTX
|
||||
activates context sensitive branch coverage - meaning that each edge
|
||||
is additionally combined with its caller.
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
||||
|
||||
See llvm_mode/README.ngram.md
|
||||
|
||||
### LAF-INTEL
|
||||
|
||||
This great feature will split compares to series of single byte comparisons
|
||||
@ -104,7 +197,7 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
- Setting AFL_LLVM_LAF_SPLIT_COMPARES will split all floating point and
|
||||
64, 32 and 16 bit integer CMP instructions
|
||||
|
||||
See llvm_mode/README.laf-intel.md for more information.
|
||||
See llvm_mode/README.laf-intel.md for more information.
|
||||
|
||||
### WHITELIST
|
||||
|
||||
@ -115,19 +208,6 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
|
||||
See llvm_mode/README.whitelist.md for more information.
|
||||
|
||||
### INSTRIM
|
||||
|
||||
This feature increases the speed by whopping 20% but at the cost of a
|
||||
lower path discovery and therefore coverage.
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM activates this mode
|
||||
|
||||
- Setting AFL_LLVM_INSTRIM_LOOPHEAD=1 expands on INSTRIM to optimize loops.
|
||||
afl-fuzz will only be able to see the path the loop took, but not how
|
||||
many times it was called (unless it is a complex loop).
|
||||
|
||||
See llvm_mode/README.instrim.md
|
||||
|
||||
### NOT_ZERO
|
||||
|
||||
- Setting AFL_LLVM_NOT_ZERO=1 during compilation will use counters
|
||||
@ -136,6 +216,10 @@ Then there are a few specific features that are only available in llvm_mode:
|
||||
slowdown due a performance issue that is only fixed in llvm 9+.
|
||||
This feature increases path discovery by a little bit.
|
||||
|
||||
- Setting AFL_LLVM_SKIP_NEVERZERO=1 will not implement the skip zero
|
||||
test. If the target performs only few loops then this will give a
|
||||
small performance boost.
|
||||
|
||||
See llvm_mode/README.neverzero.md
|
||||
|
||||
### CMPLOG
|
||||
@ -179,6 +263,11 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
normally indicated by the cycle counter in the UI turning green. May be
|
||||
convenient for some types of automated jobs.
|
||||
|
||||
- AFL_MAP_SIZE sets the size of the shared map that afl-fuzz, afl-showmap,
|
||||
afl-tmin and afl-analyze create to gather instrumentation data from
|
||||
the target. This must be equal or larger than the size the target was
|
||||
compiled with.
|
||||
|
||||
- Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core
|
||||
on Linux systems. This slows things down, but lets you run more instances
|
||||
of afl-fuzz than would be prudent (if you really want to).
|
||||
@ -192,12 +281,15 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
deciding if a particular test case is a "hang". The default is 1 second
|
||||
or the value of the -t parameter, whichever is larger. Dialing the value
|
||||
down can be useful if you are very concerned about slow inputs, or if you
|
||||
don't want AFL to spend too much time classifying that stuff and just
|
||||
don't want AFL to spend too much time classifying that stuff and just
|
||||
rapidly put all timeouts in that bin.
|
||||
|
||||
- AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics.
|
||||
This can be useful to speed up the fuzzing of text-based file formats.
|
||||
|
||||
- AFL_NO_SNAPSHOT will advice afl-fuzz not to use the snapshot feature
|
||||
if the snapshot lkm is loaded
|
||||
|
||||
- AFL_SHUFFLE_QUEUE randomly reorders the input queue on startup. Requested
|
||||
by some users for unorthodox parallelized fuzzing setups, but not
|
||||
advisable otherwise.
|
||||
@ -218,19 +310,19 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
else. This makes the "own finds" counter in the UI more accurate.
|
||||
Beyond counter aesthetics, not much else should change.
|
||||
|
||||
- Setting AFL_POST_LIBRARY allows you to configure a postprocessor for
|
||||
mutated files - say, to fix up checksums. See examples/post_library/
|
||||
for more.
|
||||
- Note that AFL_POST_LIBRARY is deprecated, use AFL_CUSTOM_MUTATOR_LIBRARY
|
||||
instead (see below).
|
||||
|
||||
- Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with
|
||||
afl_custom_mutator() export run additional mutations though this library.
|
||||
afl_custom_fuzz() creates additional mutations through this library.
|
||||
If afl-fuzz is compiled with Python (which is autodetected during builing
|
||||
afl-fuzz), setting AFL_PYTHON_MODULE to a Python module can also provide
|
||||
additional mutations.
|
||||
If AFL_CUSTOM_MUTATOR_ONLY is also set, all mutations will solely be
|
||||
performed with/from the libary. see [custom_mutator.md](custom_mutator.md)
|
||||
|
||||
- For AFL_PYTHON_MODULE and AFL_PYTHON_ONLY - they require to be compiled
|
||||
with -DUSE_PYTHON. Please see [python_mutators.md](python_mutators.md)
|
||||
This feature allows to configure custom mutators which can be very helpful
|
||||
in e.g. fuzzing XML or other highly flexible structured input.
|
||||
performed with the custom mutator.
|
||||
This feature allows to configure custom mutators which can be very helpful,
|
||||
e.g. fuzzing XML or other highly flexible structured input.
|
||||
Please see [custom_mutators.md](custom_mutators.md).
|
||||
|
||||
- AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less
|
||||
precise), which can help when starting a session against a slow target.
|
||||
@ -262,6 +354,16 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
- Setting AFL_DEBUG_CHILD_OUTPUT will not suppress the child output.
|
||||
Not pretty but good for debugging purposes.
|
||||
|
||||
- Setting AFL_NO_CPU_RED will not display very high cpu usages in red color.
|
||||
|
||||
- Setting AFL_AUTORESUME will resume a fuzz run (same as providing `-i -`)
|
||||
for an existing out folder, even if a different `-i` was provided.
|
||||
Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir.
|
||||
|
||||
- Outdated environment variables that are that not supported anymore:
|
||||
AFL_DEFER_FORKSRV
|
||||
AFL_PERSISTENT
|
||||
|
||||
## 4) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
@ -272,7 +374,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
|
||||
- Setting AFL_INST_LIBS causes the translator to also instrument the code
|
||||
inside any dynamically linked libraries (notably including glibc).
|
||||
|
||||
|
||||
- Setting AFL_COMPCOV_LEVEL enables the CompareCoverage tracing of all cmp
|
||||
and sub in x86 and x86_64 and memory comparions functions (e.g. strcmp,
|
||||
memcmp, ...) when libcompcov is preloaded using AFL_PRELOAD.
|
||||
@ -281,7 +383,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
only comparisons with immediate values / read-only memory and
|
||||
AFL_COMPCOV_LEVEL=2 that instruments all the comparions. Level 2 is more
|
||||
accurate but may need a larger shared memory.
|
||||
|
||||
|
||||
- Setting AFL_QEMU_COMPCOV enables the CompareCoverage tracing of all
|
||||
cmp and sub in x86 and x86_64.
|
||||
This is an alias of AFL_COMPCOV_LEVEL=1 when AFL_COMPCOV_LEVEL is
|
||||
@ -293,25 +395,25 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
|
||||
- AFL_DEBUG will print the found entrypoint for the binary to stderr.
|
||||
Use this if you are unsure if the entrypoint might be wrong - but
|
||||
use it directly, e.g. afl-qemu-trace ./program
|
||||
use it directly, e.g. afl-qemu-trace ./program
|
||||
|
||||
- AFL_ENTRYPOINT allows you to specify a specific entrypoint into the
|
||||
binary (this can be very good for the performance!).
|
||||
The entrypoint is specified as hex address, e.g. 0x4004110
|
||||
Note that the address must be the address of a basic block.
|
||||
|
||||
|
||||
- When the target is i386/x86_64 you can specify the address of the function
|
||||
that has to be the body of the persistent loop using
|
||||
AFL_QEMU_PERSISTENT_ADDR=`start addr`.
|
||||
|
||||
|
||||
- Another modality to execute the persistent loop is to specify also the
|
||||
AFL_QEMU_PERSISTENT_RET=`end addr` env variable.
|
||||
With this variable assigned, instead of patching the return address, the
|
||||
specified instruction is transformed to a jump towards `start addr`.
|
||||
|
||||
|
||||
- AFL_QEMU_PERSISTENT_GPR=1 QEMU will save the original value of general
|
||||
purpose registers and restore them in each persistent cycle.
|
||||
|
||||
|
||||
- With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the
|
||||
stack pointer in which QEMU can find the return address when `start addr` is
|
||||
hitted.
|
||||
@ -365,7 +467,7 @@ The library honors these environmental variables:
|
||||
- AFL_LD_NO_CALLOC_OVER inhibits abort() on calloc() overflows. Most
|
||||
of the common allocators check for that internally and return NULL, so
|
||||
it's a security risk only in more exotic setups.
|
||||
|
||||
|
||||
- AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to
|
||||
max_align_t to be compliant with the C standard.
|
||||
|
||||
@ -399,7 +501,7 @@ optimal values if not already present in the environment:
|
||||
|
||||
- In the same vein, by default, MSAN_OPTIONS are set to:
|
||||
|
||||
exit_code=86 (required for legacy reasons)
|
||||
exit_code=86 (required for legacy reasons)
|
||||
abort_on_error=1
|
||||
symbolize=0
|
||||
msan_track_origins=0
|
||||
@ -408,3 +510,4 @@ optimal values if not already present in the environment:
|
||||
Be sure to include the first one when customizing anything, since some
|
||||
MSAN versions don't call abort() on error, and we need a way to detect
|
||||
faults.
|
||||
|
||||
|
@ -3,6 +3,9 @@
|
||||
In the following, we describe a variety of ideas that could be implemented
|
||||
for future AFL++ versions.
|
||||
|
||||
For GSOC2020 interested students please see
|
||||
[https://github.com/AFLplusplus/AFLplusplus/issues/208](https://github.com/AFLplusplus/AFLplusplus/issues/208)
|
||||
|
||||
## Flexible Grammar Mutator
|
||||
|
||||
Currently, AFL++'s mutation does not have deeper knowledge about the fuzzed
|
||||
@ -30,7 +33,7 @@ This is an excellent mutations scheduler based on Particle Swarm
|
||||
Optimization but the current implementation schedule only the mutations
|
||||
that were present on AFL.
|
||||
|
||||
AFL++ added a lost of optional mutators like the Input-2-State one based
|
||||
AFL++ added a lot of optional mutators like the Input-2-State one based
|
||||
on Redqueen, the Radamsa mutator, the Custom mutator (the user can define
|
||||
its own mutator) and the work is to generalize MOpt for all the current
|
||||
and future mutators.
|
||||
@ -39,16 +42,17 @@ Mentor: vanhauser-thc or andreafioraldi
|
||||
|
||||
## perf-fuzz Linux Kernel Module
|
||||
|
||||
Port the parts of the Linux Kernel modified by
|
||||
Either Port the patch to the upcoming Ubuntu LTS 20.04 default kernel
|
||||
and provide a qemu-kvm image or find a different userspace snapshot
|
||||
solution that has a good performance and is reliable, e.g. with docker.
|
||||
[perf-fuzz](https://gts3.org/assets/papers/2017/xu:os-fuzz.pdf)
|
||||
into a linux kernel module, so no source in the kernel needs to be changed.
|
||||
Or write your worn LKM from scratch to do this.
|
||||
The perf-fuzz kernel can be found at [https://github.com/sslab-gatech/perf-fuzz](https://github.com/sslab-gatech/perf-fuzz)
|
||||
There also is/was a FreeBSD project at [https://github.com/veracode-research/freebsd-perf-fuzz](https://github.com/veracode-research/freebsd-perf-fuzz)
|
||||
|
||||
This enables snapshot fuzzing on Linux with an incredible performance!
|
||||
|
||||
Mentor: any
|
||||
Idea/Issue tracker: [https://github.com/AFLplusplus/AFLplusplus/issues/248](https://github.com/AFLplusplus/AFLplusplus/issues/248)
|
||||
|
||||
## QEMU 4-based Instrumentation
|
||||
|
||||
@ -84,22 +88,33 @@ Mentor: domenukk
|
||||
|
||||
## Reengineer `afl-fuzz` as Thread Safe, Embeddable Library
|
||||
|
||||
Right now, afl-fuzz is single threaded, cannot safely be embedded in tools, and not multi-threaded. It makes use of a large number of globals, must always be the parent process and exec child processes.
|
||||
Right now, afl-fuzz is single threaded, cannot safely be embedded in tools,
|
||||
and not multi-threaded. It makes use of a large number of globals, must always
|
||||
be the parent process and exec child processes.
|
||||
Instead, afl-fuzz could be refactored to contain no global state and globals.
|
||||
This allows for different use cases that could be implemented during this project.
|
||||
This allows for different use cases that could be implemented during this
|
||||
project.
|
||||
Note that in the mean time a lot has happened here already, but e.g. making
|
||||
it all work and implement multithreading in afl-fuzz ... there is still quite
|
||||
some work to do.
|
||||
|
||||
Mentor: hexcoder- or vanhauser-thc
|
||||
|
||||
## Collision-free Binary-Only Maps
|
||||
|
||||
AFL++ supports collison-free maps using an LTO (link-time-optimization) pass.
|
||||
This should be possile to implement for QEMU and Unicorn instrumentations.
|
||||
As the forkserver parent caches just in time translated translation blocks, adding a simple counter between jumps should be doable.
|
||||
This should be possible to implement for QEMU and Unicorn instrumentations.
|
||||
As the forkserver parent caches just in time translated translation blocks,
|
||||
adding a simple counter between jumps should be doable.
|
||||
|
||||
Note: this is already in development for qemu by Andrea, so for people who
|
||||
want to contribute it might make more sense to port his solution to unicorn.
|
||||
|
||||
Mentor: andreafioraldi or domenukk
|
||||
Issue/idea tracker: [https://github.com/AFLplusplus/AFLplusplus/issues/237](https://github.com/AFLplusplus/AFLplusplus/issues/237)
|
||||
|
||||
## Your idea!
|
||||
|
||||
Finally, we are open to proposals!
|
||||
Create an issue at https://github.com/vanhauser-thc/AFLplusplus/issues and let's discuss :-)
|
||||
Create an issue at https://github.com/AFLplusplus/AFLplusplus/issues and let's discuss :-)
|
||||
|
||||
|
@ -28,6 +28,10 @@ Note that ASAN is incompatible with -static, so be mindful of that.
|
||||
|
||||
(You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
|
||||
|
||||
NOTE: if you run several slaves only one should run the target compiled with
|
||||
ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers
|
||||
compiled in.
|
||||
|
||||
There is also the option of generating a corpus using a non-ASAN binary, and
|
||||
then feeding it to an ASAN-instrumented one to check for bugs. This is faster,
|
||||
and can give you somewhat comparable results. You can also try using
|
||||
|
@ -19,6 +19,8 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ
|
||||
| `-p quad` |  |
|
||||
| `-p lin` |  |
|
||||
| `-p exploit` (AFL) |  |
|
||||
| `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries |
|
||||
| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges |
|
||||
where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path.
|
||||
|
||||
More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/).
|
||||
|
@ -1,148 +0,0 @@
|
||||
# Adding custom mutators to AFL using Python modules
|
||||
|
||||
This file describes how you can utilize the external Python API to write
|
||||
your own custom mutation routines.
|
||||
|
||||
Note: This feature is highly experimental. Use at your own risk.
|
||||
|
||||
Implemented by Christian Holler (:decoder) <choller@mozilla.com>.
|
||||
|
||||
NOTE: Only cPython 2.7, 3.7 and above are supported, although others may work.
|
||||
Depending on with which version afl-fuzz was compiled against, you must use
|
||||
python2 or python3 syntax in your scripts!
|
||||
After a major version upgrade (e.g. 3.7 -> 3.8), a recompilation of afl-fuzz may be needed.
|
||||
|
||||
For an example and a template see ../examples/python_mutators/
|
||||
|
||||
|
||||
## 1) Description and purpose
|
||||
|
||||
While AFLFuzz comes with a good selection of generic deterministic and
|
||||
non-deterministic mutation operations, it sometimes might make sense to extend
|
||||
these to implement strategies more specific to the target you are fuzzing.
|
||||
|
||||
For simplicity and in order to allow people without C knowledge to extend
|
||||
AFLFuzz, I implemented a "Python" stage that can make use of an external
|
||||
module (written in Python) that implements a custom mutation stage.
|
||||
|
||||
The main motivation behind this is to lower the barrier for people
|
||||
experimenting with this tool. Hopefully, someone will be able to do useful
|
||||
things with this extension.
|
||||
|
||||
If you find it useful, have questions or need additional features added to the
|
||||
interface, feel free to send a mail to <choller@mozilla.com>.
|
||||
|
||||
See the following information to get a better pictures:
|
||||
https://www.agarri.fr/docs/XML_Fuzzing-NullCon2017-PUBLIC.pdf
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=930663
|
||||
|
||||
|
||||
## 2) How the Python module looks like
|
||||
|
||||
You can find a simple example in pymodules/example.py including documentation
|
||||
explaining each function. In the same directory, you can find another simple
|
||||
module that performs simple mutations.
|
||||
|
||||
Right now, "init" is called at program startup and can be used to perform any
|
||||
kinds of one-time initializations while "fuzz" is called each time a mutation
|
||||
is requested.
|
||||
|
||||
There is also optional support for a trimming API, see the section below for
|
||||
further information about this feature.
|
||||
|
||||
|
||||
## 3) How to compile AFLFuzz with Python support
|
||||
|
||||
You must install the python 3 or 2 development package of your Linux
|
||||
distribution before this will work. On Debian/Ubuntu/Kali this can be done
|
||||
with either:
|
||||
apt install python3-dev
|
||||
or
|
||||
apt install python-dev
|
||||
Note that for some distributions you might also need the package python[23]-apt
|
||||
|
||||
A prerequisite for using this mode is to compile AFLFuzz with Python support.
|
||||
|
||||
The AFL++ Makefile detects Python 3 and 2 through `python-config` if is is in the PATH
|
||||
and compiles afl-fuzz with the feature if available.
|
||||
|
||||
In case your setup is different set the necessary variables like this:
|
||||
PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make
|
||||
|
||||
|
||||
## 4) How to run AFLFuzz with your custom module
|
||||
|
||||
You must pass the module name inside the env variable AFL_PYTHON_MODULE.
|
||||
|
||||
In addition, if you are trying to load the module from the local directory,
|
||||
you must adjust your PYTHONPATH to reflect this circumstance. The following
|
||||
command should work if you are inside the aflfuzz directory:
|
||||
|
||||
$ AFL_PYTHON_MODULE="pymodules.test" PYTHONPATH=. ./afl-fuzz
|
||||
|
||||
Optionally, the following environment variables are supported:
|
||||
|
||||
AFL_PYTHON_ONLY - Disable all other mutation stages. This can prevent broken
|
||||
testcases (those that your Python module can't work with
|
||||
anymore) to fill up your queue. Best combined with a custom
|
||||
trimming routine (see below) because trimming can cause the
|
||||
same test breakage like havoc and splice.
|
||||
|
||||
AFL_DEBUG - When combined with AFL_NO_UI, this causes the C trimming code
|
||||
to emit additional messages about the performance and actions
|
||||
of your custom Python trimmer. Use this to see if it works :)
|
||||
|
||||
|
||||
## 5) Order and statistics
|
||||
|
||||
The Python stage is set to be the first non-deterministic stage (right before
|
||||
the havoc stage). In the statistics however, it shows up as the third number
|
||||
under "havoc". That's because I'm lazy and I didn't want to mess with the UI
|
||||
too much ;)
|
||||
|
||||
|
||||
## 6) Trimming support
|
||||
|
||||
The generic trimming routines implemented in AFLFuzz can easily destroy the
|
||||
structure of complex formats, possibly leading to a point where you have a lot
|
||||
of testcases in the queue that your Python module cannot process anymore but
|
||||
your target application still accepts. This is especially the case when your
|
||||
target can process a part of the input (causing coverage) and then errors out
|
||||
on the remaining input.
|
||||
|
||||
In such cases, it makes sense to implement a custom trimming routine in Python.
|
||||
The API consists of multiple methods because after each trimming step, we have
|
||||
to go back into the C code to check if the coverage bitmap is still the same
|
||||
for the trimmed input. Here's a quick API description:
|
||||
|
||||
init_trim: This method is called at the start of each trimming operation
|
||||
and receives the initial buffer. It should return the amount
|
||||
of iteration steps possible on this input (e.g. if your input
|
||||
has n elements and you want to remove them one by one, return n,
|
||||
if you do a binary search, return log(n), and so on...).
|
||||
|
||||
If your trimming algorithm doesn't allow you to determine the
|
||||
amount of (remaining) steps easily (esp. while running), then you
|
||||
can alternatively return 1 here and always return 0 in post_trim
|
||||
until you are finished and no steps remain. In that case,
|
||||
returning 1 in post_trim will end the trimming routine. The whole
|
||||
current index/max iterations stuff is only used to show progress.
|
||||
|
||||
trim: This method is called for each trimming operation. It doesn't
|
||||
have any arguments because we already have the initial buffer
|
||||
from init_trim and we can memorize the current state in global
|
||||
variables. This can also save reparsing steps for each iteration.
|
||||
It should return the trimmed input buffer, where the returned data
|
||||
must not exceed the initial input data in length. Returning anything
|
||||
that is larger than the original data (passed to init_trim) will
|
||||
result in a fatal abort of AFLFuzz.
|
||||
|
||||
post_trim: This method is called after each trim operation to inform you
|
||||
if your trimming step was successful or not (in terms of coverage).
|
||||
If you receive a failure here, you should reset your input to the
|
||||
last known good state.
|
||||
In any case, this method must return the next trim iteration index
|
||||
(from 0 to the maximum amount of steps you returned in init_trim).
|
||||
|
||||
Omitting any of the methods will cause Python trimming to be disabled and
|
||||
trigger a fallback to the builtin default trimming routine.
|
@ -56,13 +56,6 @@ functionality is now available as the "persistent" feature described in
|
||||
|
||||
http://llvm.org/docs/LibFuzzer.html
|
||||
|
||||
## AFL fixup shim (Ben Nagy)
|
||||
|
||||
Allows AFL_POST_LIBRARY postprocessors to be written in arbitrary languages
|
||||
that don't have C / .so bindings. Includes examples in Go.
|
||||
|
||||
https://github.com/bnagy/aflfix
|
||||
|
||||
## TriforceAFL (Tim Newsham and Jesse Hertz)
|
||||
|
||||
Leverages QEMU full system emulation mode to allow AFL to target operating
|
||||
|
@ -372,26 +372,40 @@ For unattended operation, some of the key status screen information can be also
|
||||
found in a machine-readable format in the fuzzer_stats file in the output
|
||||
directory. This includes:
|
||||
|
||||
- `start_time` - unix time indicating the start time of afl-fuzz
|
||||
- `last_update` - unix time corresponding to the last update of this file
|
||||
- `fuzzer_pid` - PID of the fuzzer process
|
||||
- `cycles_done` - queue cycles completed so far
|
||||
- `execs_done` - number of execve() calls attempted
|
||||
- `execs_per_sec` - overall number of execs per second
|
||||
- `paths_total` - total number of entries in the queue
|
||||
- `paths_found` - number of entries discovered through local fuzzing
|
||||
- `paths_imported` - number of entries imported from other instances
|
||||
- `max_depth` - number of levels in the generated data set
|
||||
- `cur_path` - currently processed entry number
|
||||
- `pending_favs` - number of favored entries still waiting to be fuzzed
|
||||
- `pending_total` - number of all entries waiting to be fuzzed
|
||||
- `stability - percentage of bitmap bytes that behave consistently
|
||||
- `variable_paths` - number of test cases showing variable behavior
|
||||
- `unique_crashes` - number of unique crashes recorded
|
||||
- `unique_hangs` - number of unique hangs encountered
|
||||
- `command_line` - full command line used for the fuzzing session
|
||||
- `slowest_exec_ms`- real time of the slowest execution in seconds
|
||||
- `peak_rss_mb` - max rss usage reached during fuzzing in MB
|
||||
- `start_time` - unix time indicating the start time of afl-fuzz
|
||||
- `last_update` - unix time corresponding to the last update of this file
|
||||
- `run_time` - run time in seconds to the last update of this file
|
||||
- `fuzzer_pid` - PID of the fuzzer process
|
||||
- `cycles_done` - queue cycles completed so far
|
||||
- `cycles_wo_finds` - number of cycles without any new paths found
|
||||
- `execs_done` - number of execve() calls attempted
|
||||
- `execs_per_sec` - overall number of execs per second
|
||||
- `paths_total` - total number of entries in the queue
|
||||
- `paths_favored` - number of queue entries that are favored
|
||||
- `paths_found` - number of entries discovered through local fuzzing
|
||||
- `paths_imported` - number of entries imported from other instances
|
||||
- `max_depth` - number of levels in the generated data set
|
||||
- `cur_path` - currently processed entry number
|
||||
- `pending_favs` - number of favored entries still waiting to be fuzzed
|
||||
- `pending_total` - number of all entries waiting to be fuzzed
|
||||
- `variable_paths` - number of test cases showing variable behavior
|
||||
- `stability` - percentage of bitmap bytes that behave consistently
|
||||
- `bitmap_cvg` - percentage of edge coverage found in the map so far
|
||||
- `unique_crashes` - number of unique crashes recorded
|
||||
- `unique_hangs` - number of unique hangs encountered
|
||||
- `last_path` - seconds since the last path was found
|
||||
- `last_crash` - seconds since the last crash was found
|
||||
- `last_hang` - seconds since the last hang was found
|
||||
- `execs_since_crash` - execs since the last crash was found
|
||||
- `exec_timeout` - the -t command line value
|
||||
- `slowest_exec_ms` - real time of the slowest execution in ms
|
||||
- `peak_rss_mb` - max rss usage reached during fuzzing in MB
|
||||
- `edges_found` - how many edges have been found
|
||||
- `var_byte_count` - how many edges are non-deterministic
|
||||
- `afl_banner` - banner text (e.g. the target name)
|
||||
- `afl_version` - the version of afl used
|
||||
- `target_mode` - default, persistent, qemu, unicorn, dumb
|
||||
- `command_line` - full command line used for the fuzzing session
|
||||
|
||||
Most of these map directly to the UI elements discussed earlier on.
|
||||
|
||||
|
@ -286,8 +286,9 @@ operation of `afl-tmin` is as follows.
|
||||
|
||||
First, the tool automatically selects the operating mode. If the initial input
|
||||
crashes the target binary, afl-tmin will run in non-instrumented mode, simply
|
||||
keeping any tweaks that produce a simpler file but still crash the target. If
|
||||
the target is non-crashing, the tool uses an instrumented mode and keeps only
|
||||
keeping any tweaks that produce a simpler file but still crash the target.
|
||||
The same mode is used for hangs, if `-H` (hang mode) is specified.
|
||||
If the target is non-crashing, the tool uses an instrumented mode and keeps only
|
||||
the tweaks that produce exactly the same execution path.
|
||||
|
||||
The actual minimization algorithm is:
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
Here's a quick overview of the stuff you can find in this directory:
|
||||
|
||||
- custom_mutstors - An example custom mutator
|
||||
|
||||
- python_mutators - Python mutators examples
|
||||
- custom_mutators - example custom mutators in python an c
|
||||
|
||||
- argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed
|
||||
(e.g., to test setuid programs).
|
||||
@ -15,8 +13,8 @@ Here's a quick overview of the stuff you can find in this directory:
|
||||
- bash_shellshock - a simple hack used to find a bunch of
|
||||
post-Shellshock bugs in bash.
|
||||
|
||||
- canvas_harness - a test harness used to find browser bugs with a
|
||||
corpus generated using simple image parsing
|
||||
- canvas_harness - a test harness used to find browser bugs with a
|
||||
corpus generated using simple image parsing
|
||||
binaries & afl-fuzz.
|
||||
|
||||
- clang_asm_normalize - a script that makes it easy to instrument
|
||||
@ -34,7 +32,7 @@ Here's a quick overview of the stuff you can find in this directory:
|
||||
mode to speed up certain fuzzing jobs.
|
||||
|
||||
- post_library - an example of how to build postprocessors for AFL.
|
||||
|
||||
|
||||
- socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
|
||||
for fuzzing access with afl++
|
||||
|
||||
|
43
examples/afl_network_proxy/GNUmakefile
Normal file
43
examples/afl_network_proxy/GNUmakefile
Normal file
@ -0,0 +1,43 @@
|
||||
PREFIX ?= /usr/local
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
|
||||
PROGRAMS = afl-network-client afl-network-server
|
||||
|
||||
HASH=\#
|
||||
|
||||
CFLAGS += -Wno-pointer-sign
|
||||
|
||||
ifdef STATIC
|
||||
CFLAGS += -static
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <libdeflate.h>@int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
CFLAGS += -DUSE_DEFLATE=1
|
||||
LDFLAGS += -ldeflate
|
||||
$(info libdeflate-dev was detected, using compression)
|
||||
else
|
||||
$(warn did not find libdeflate-dev, cannot use compression)
|
||||
endif
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
help:
|
||||
@echo make options:
|
||||
@echo STATIC - build as static binaries
|
||||
@echo COMPRESS_TESTCASES - compress test cases
|
||||
|
||||
afl-network-client: afl-network-client.c
|
||||
$(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS)
|
||||
|
||||
afl-network-server: afl-network-server.c
|
||||
$(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAMS) *~ core
|
||||
|
||||
install: all
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH)
|
||||
install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH)
|
||||
install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md
|
||||
|
2
examples/afl_network_proxy/Makefile
Normal file
2
examples/afl_network_proxy/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
all:
|
||||
@echo please use GNU make, thanks!
|
61
examples/afl_network_proxy/README.md
Normal file
61
examples/afl_network_proxy/README.md
Normal file
@ -0,0 +1,61 @@
|
||||
# afl-network-proxy
|
||||
|
||||
If you want to run afl-fuzz over the network than this is what you need :)
|
||||
Note that the impact on fuzzing speed will be huge, expect a loss of 90%.
|
||||
|
||||
## When to use this
|
||||
|
||||
1. when you have to fuzz a target that has to run on a system that cannot
|
||||
contain the fuzzing output (e.g. /tmp too small and file system is read-only)
|
||||
2. when the target instantly reboots on crashes
|
||||
3. ... any other reason you would need this
|
||||
|
||||
## how to get it running
|
||||
|
||||
### Compiling
|
||||
|
||||
Just type `make` and let the autodetection do everything for you.
|
||||
|
||||
Note that you will get a 40-50% performance increase if you have libdeflate-dev
|
||||
installed. The GNUmakefile will autodetect it if present.
|
||||
|
||||
If your target has large test cases (10+kb) that are ascii only or large chunks
|
||||
of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them.
|
||||
For most targets this hurts performance though so it is disabled by default.
|
||||
|
||||
### on the target
|
||||
|
||||
Run `afl-network-server` with your target with the -m and -t values you need.
|
||||
Important is the -i parameter which is the TCP port to listen on.
|
||||
e.g.:
|
||||
```
|
||||
$ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@
|
||||
```
|
||||
|
||||
### on the (afl-fuzz) master
|
||||
|
||||
Just run afl-fuzz with your normal options, however the target should be
|
||||
`afl-network-client` with the IP and PORT of the `afl-network-server` and
|
||||
increase the -t value:
|
||||
```
|
||||
$ afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111
|
||||
```
|
||||
Note the '+' on the -t parameter value. The afl-network-server will take
|
||||
care of proper timeouts hence afl-fuzz should not. The '+' increases the
|
||||
timeout and the value itself should be 500-1000 higher than the one on
|
||||
afl-network-server.
|
||||
|
||||
### networking
|
||||
|
||||
The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to
|
||||
either. Note that also the outgoing interface can be specified with a '%' for
|
||||
`afl-network-client`, e.g. `fe80::1234%eth0`.
|
||||
|
||||
Also make sure your default TCP window size is larger than your MAP_SIZE
|
||||
(130kb is a good value).
|
||||
On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem`
|
||||
|
||||
## how to compile and install
|
||||
|
||||
`make && sudo make install`
|
||||
|
413
examples/afl_network_proxy/afl-network-client.c
Normal file
413
examples/afl_network_proxy/afl-network-client.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
american fuzzy lop++ - afl-network-client
|
||||
---------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de>
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
#include <libdeflate.h>
|
||||
#endif
|
||||
|
||||
u8 *__afl_area_ptr;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_map_size = MAP_SIZE;
|
||||
#else
|
||||
__thread u32 __afl_map_size = MAP_SIZE;
|
||||
#endif
|
||||
|
||||
/* Error reporting to forkserver controller */
|
||||
|
||||
void send_forkserver_error(int error) {
|
||||
|
||||
u32 status;
|
||||
if (!error || error > 0xffff) return;
|
||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
|
||||
|
||||
}
|
||||
|
||||
/* SHM setup. */
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
char *ptr;
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
|
||||
|
||||
u32 val = atoi(ptr);
|
||||
if (val > 0) __afl_map_size = val;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_map_size > MAP_SIZE) {
|
||||
|
||||
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
if (id_str) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr,
|
||||
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
unsigned char *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* map the shared memory segment to the address space of the process */
|
||||
shm_base =
|
||||
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
if (shm_base == MAP_FAILED) {
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
send_forkserver_error(FS_ERROR_MMAP);
|
||||
exit(2);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = shm_base;
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, 0, 0);
|
||||
|
||||
#endif
|
||||
|
||||
if (__afl_area_ptr == (void *)-1) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_SHMAT);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* Write something into the bitmap so that the parent doesn't give up */
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic. */
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 status = 0;
|
||||
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
|
||||
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
if (status) status |= (FS_OPT_ENABLED);
|
||||
memcpy(tmp, &status, 4);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
|
||||
}
|
||||
|
||||
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
|
||||
s32 status, res = 0x0fffffff; // res is a dummy pid
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
if (read(FORKSRV_FD, &status, 4) != 4) return 0;
|
||||
|
||||
/* we have a testcase - read it */
|
||||
status = read(0, buf, max_len);
|
||||
|
||||
/* report that we are starting the target */
|
||||
if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
|
||||
|
||||
if (status < 1)
|
||||
return 0;
|
||||
else
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static void __afl_end_testcase(int status) {
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* you just need to modify the while() loop in this main() */
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
u8 * interface, *buf, *ptr;
|
||||
s32 s = -1;
|
||||
struct addrinfo hints, *hres, *aip;
|
||||
u32 * lenptr, max_len = 65536;
|
||||
#ifdef USE_DEFLATE
|
||||
u8 * buf2;
|
||||
u32 * lenptr1, *lenptr2, buf2_len, compress_len;
|
||||
size_t decompress_len;
|
||||
#endif
|
||||
|
||||
if (argc < 3 || argc > 4) {
|
||||
|
||||
printf("Syntax: %s host port [max-input-size]\n\n", argv[0]);
|
||||
printf("Requires host and port of the remote afl-proxy-server instance.\n");
|
||||
printf(
|
||||
"IPv4 and IPv6 are supported, also binding to an interface with "
|
||||
"\"%%\"\n");
|
||||
printf("The max-input-size default is %u.\n", max_len);
|
||||
printf(
|
||||
"The default map size is %u and can be changed with setting "
|
||||
"AFL_MAP_SIZE.\n",
|
||||
__afl_map_size);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
if ((interface = index(argv[1], '%')) != NULL) *interface++ = 0;
|
||||
|
||||
if (argc > 3)
|
||||
if ((max_len = atoi(argv[3])) < 0)
|
||||
FATAL("max-input-size may not be negative or larger than 2GB: %s",
|
||||
argv[3]);
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL)
|
||||
if ((__afl_map_size = atoi(ptr)) < 8)
|
||||
FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr);
|
||||
|
||||
if ((buf = malloc(max_len + 4)) == NULL)
|
||||
PFATAL("can not allocate %u memory", max_len + 4);
|
||||
lenptr = (u32 *)buf;
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size);
|
||||
if ((buf2 = malloc(buf2_len + 8)) == NULL)
|
||||
PFATAL("can not allocate %u memory", buf2_len + 8);
|
||||
lenptr1 = (u32 *)buf2;
|
||||
lenptr2 = (u32 *)(buf2 + 4);
|
||||
#endif
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0)
|
||||
PFATAL("could not resolve target %s", argv[1]);
|
||||
|
||||
for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) {
|
||||
|
||||
if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) {
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
if (interface != NULL)
|
||||
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
|
||||
strlen(interface) + 1) < 0)
|
||||
fprintf(stderr, "Warning: could not bind to device %s\n", interface);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"Warning: binding to interface is not supported for your OS\n");
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
int priority = 7;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
|
||||
0) {
|
||||
|
||||
priority = 6;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority,
|
||||
sizeof(priority)) < 0)
|
||||
WARNF("could not set priority on socket");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
struct libdeflate_compressor *compressor;
|
||||
compressor = libdeflate_alloc_compressor(1);
|
||||
struct libdeflate_decompressor *decompressor;
|
||||
decompressor = libdeflate_alloc_decompressor();
|
||||
fprintf(stderr, "Compiled with compression support\n");
|
||||
#endif
|
||||
|
||||
if (s == -1)
|
||||
FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]);
|
||||
else
|
||||
fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]);
|
||||
|
||||
/* we initialize the shared memory map and start the forkserver */
|
||||
__afl_map_shm();
|
||||
__afl_start_forkserver();
|
||||
|
||||
int i = 1, j, status, ret, received;
|
||||
|
||||
// fprintf(stderr, "Waiting for first testcase\n");
|
||||
while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) {
|
||||
|
||||
// fprintf(stderr, "Sending testcase with len %u\n", *lenptr);
|
||||
#ifdef USE_DEFLATE
|
||||
#ifdef COMPRESS_TESTCASES
|
||||
// we only compress the testcase if it does not fit in the TCP packet
|
||||
if (*lenptr > 1500 - 20 - 32 - 4) {
|
||||
|
||||
// set highest byte to signify compression
|
||||
*lenptr1 = (*lenptr | 0xff000000);
|
||||
*lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr,
|
||||
buf2 + 8, buf2_len);
|
||||
if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8)
|
||||
PFATAL("sending test data failed");
|
||||
// fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2);
|
||||
// for (u32 i = 0; i < *lenptr; i++)
|
||||
// fprintf(stderr, "%02x", buf[i + 4]);
|
||||
// fprintf(stderr, "\n");
|
||||
// for (u32 i = 0; i < *lenptr2; i++)
|
||||
// fprintf(stderr, "%02x", buf2[i + 8]);
|
||||
// fprintf(stderr, "\n");
|
||||
|
||||
} else {
|
||||
|
||||
#endif
|
||||
#endif
|
||||
if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4)
|
||||
PFATAL("sending test data failed");
|
||||
#ifdef USE_DEFLATE
|
||||
#ifdef COMPRESS_TESTCASES
|
||||
// fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
received = 0;
|
||||
while (received < 4 &&
|
||||
(ret = recv(s, &status + received, 4 - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != 4)
|
||||
FATAL("did not receive waitpid data (%d, %d)", received, ret);
|
||||
// fprintf(stderr, "Received status\n");
|
||||
|
||||
received = 0;
|
||||
#ifdef USE_DEFLATE
|
||||
while (received < 4 &&
|
||||
(ret = recv(s, &compress_len + received, 4 - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != 4)
|
||||
FATAL("did not receive compress_len (%d, %d)", received, ret);
|
||||
// fprintf(stderr, "Received status\n");
|
||||
|
||||
received = 0;
|
||||
while (received < compress_len &&
|
||||
(ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != compress_len)
|
||||
FATAL("did not receive coverage data (%d, %d)", received, ret);
|
||||
|
||||
if (libdeflate_deflate_decompress(decompressor, buf2, compress_len,
|
||||
__afl_area_ptr, __afl_map_size,
|
||||
&decompress_len) != LIBDEFLATE_SUCCESS ||
|
||||
decompress_len != __afl_map_size)
|
||||
FATAL("decompression failed");
|
||||
// fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len);
|
||||
// for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x",
|
||||
// __afl_area_ptr[i]); fprintf(stderr, "\n");
|
||||
#else
|
||||
while (received < __afl_map_size &&
|
||||
(ret = recv(s, __afl_area_ptr + received, __afl_map_size - received,
|
||||
0)) > 0)
|
||||
received += ret;
|
||||
if (received != __afl_map_size)
|
||||
FATAL("did not receive coverage data (%d, %d)", received, ret);
|
||||
#endif
|
||||
// fprintf(stderr, "Received coverage\n");
|
||||
|
||||
/* report the test case is done and wait for the next */
|
||||
__afl_end_testcase(status);
|
||||
// fprintf(stderr, "Waiting for next testcase %d\n", ++i);
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
libdeflate_free_compressor(compressor);
|
||||
libdeflate_free_decompressor(decompressor);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
712
examples/afl_network_proxy/afl-network-server.c
Normal file
712
examples/afl_network_proxy/afl-network-server.c
Normal file
@ -0,0 +1,712 @@
|
||||
/*
|
||||
american fuzzy lop++ - network proxy server
|
||||
-------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com> and
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#define AFL_MAIN
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
#include "hash.h"
|
||||
#include "forkserver.h"
|
||||
#include "sharedmem.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
#include <libdeflate.h>
|
||||
struct libdeflate_compressor * compressor;
|
||||
struct libdeflate_decompressor *decompressor;
|
||||
#endif
|
||||
|
||||
static u8 *in_file, /* Minimizer input test case */
|
||||
*out_file;
|
||||
|
||||
static u8 *in_data; /* Input data for trimming */
|
||||
static u8 *buf2;
|
||||
|
||||
static s32 in_len;
|
||||
static u32 map_size = MAP_SIZE;
|
||||
static size_t buf2_len;
|
||||
|
||||
static volatile u8 stop_soon; /* Ctrl-C pressed? */
|
||||
|
||||
/* See if any bytes are set in the bitmap. */
|
||||
|
||||
static inline u8 anything_set(afl_forkserver_t *fsrv) {
|
||||
|
||||
u32 *ptr = (u32 *)fsrv->trace_bits;
|
||||
u32 i = (map_size >> 2);
|
||||
|
||||
while (i--) {
|
||||
|
||||
if (*(ptr++)) { return 1; }
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void at_exit_handler(void) {
|
||||
|
||||
afl_fsrv_killall();
|
||||
|
||||
}
|
||||
|
||||
/* Write output file. */
|
||||
|
||||
static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
|
||||
|
||||
s32 ret;
|
||||
|
||||
unlink(path); /* Ignore errors */
|
||||
|
||||
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
|
||||
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
|
||||
|
||||
ck_write(ret, mem, len, path);
|
||||
|
||||
lseek(ret, 0, SEEK_SET);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Execute target application. Returns 0 if the changes are a dud, or
|
||||
1 if they should be kept. */
|
||||
|
||||
static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
|
||||
u8 first_run) {
|
||||
|
||||
afl_fsrv_write_to_testcase(fsrv, mem, len);
|
||||
|
||||
fsrv_run_result_t ret =
|
||||
afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
|
||||
|
||||
if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); }
|
||||
|
||||
if (stop_soon) {
|
||||
|
||||
SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Handle Ctrl-C and the like. */
|
||||
|
||||
static void handle_stop_sig(int sig) {
|
||||
|
||||
stop_soon = 1;
|
||||
afl_fsrv_killall();
|
||||
|
||||
}
|
||||
|
||||
/* Do basic preparations - persistent fds, filenames, etc. */
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
u8 *x;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
|
||||
if (!out_file) {
|
||||
|
||||
u8 *use_dir = ".";
|
||||
|
||||
if (access(use_dir, R_OK | W_OK | X_OK)) {
|
||||
|
||||
use_dir = get_afl_env("TMPDIR");
|
||||
if (!use_dir) { use_dir = "/tmp"; }
|
||||
|
||||
}
|
||||
|
||||
out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid());
|
||||
|
||||
}
|
||||
|
||||
unlink(out_file);
|
||||
|
||||
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
|
||||
|
||||
/* Set sane defaults... */
|
||||
|
||||
x = get_afl_env("ASAN_OPTIONS");
|
||||
|
||||
if (x) {
|
||||
|
||||
if (!strstr(x, "abort_on_error=1")) {
|
||||
|
||||
FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
|
||||
|
||||
}
|
||||
|
||||
if (!strstr(x, "symbolize=0")) {
|
||||
|
||||
FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
x = get_afl_env("MSAN_OPTIONS");
|
||||
|
||||
if (x) {
|
||||
|
||||
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
|
||||
|
||||
FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
|
||||
MSAN_ERROR) " - please fix!");
|
||||
|
||||
}
|
||||
|
||||
if (!strstr(x, "symbolize=0")) {
|
||||
|
||||
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setenv("ASAN_OPTIONS",
|
||||
"abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
"symbolize=0:"
|
||||
"allocator_may_return_null=1",
|
||||
0);
|
||||
|
||||
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
|
||||
"symbolize=0:"
|
||||
"abort_on_error=1:"
|
||||
"allocator_may_return_null=1:"
|
||||
"msan_track_origins=0", 0);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 i, afl_preload_size = strlen(afl_preload);
|
||||
for (i = 0; i < afl_preload_size; ++i) {
|
||||
|
||||
if (afl_preload[i] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
ck_free(buf);
|
||||
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Setup signal handlers, duh. */
|
||||
|
||||
static void setup_signal_handlers(void) {
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = NULL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_sigaction = NULL;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
/* Various ways of saying "stop". */
|
||||
|
||||
sa.sa_handler = handle_stop_sig;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* Display usage hints. */
|
||||
|
||||
static void usage(u8 *argv0) {
|
||||
|
||||
SAYF(
|
||||
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
|
||||
|
||||
"Required parameters:\n"
|
||||
|
||||
" -i port - the port to listen for the client to connect to\n\n"
|
||||
|
||||
"Execution control settings:\n"
|
||||
|
||||
" -f file - input file read by the tested program (stdin)\n"
|
||||
" -t msec - timeout for each run (%d ms)\n"
|
||||
" -m megs - memory limit for child process (%d MB)\n"
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n"
|
||||
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
|
||||
" -W - use qemu-based instrumentation with Wine (Wine "
|
||||
"mode)\n\n"
|
||||
|
||||
"Environment variables used:\n"
|
||||
"TMPDIR: directory to use for temporary input files\n"
|
||||
"ASAN_OPTIONS: custom settings for ASAN\n"
|
||||
" (must contain abort_on_error=1 and symbolize=0)\n"
|
||||
"MSAN_OPTIONS: custom settings for MSAN\n"
|
||||
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
|
||||
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
|
||||
" the target was compiled for\n"
|
||||
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
||||
|
||||
, argv0, EXEC_TIMEOUT, MEM_LIMIT);
|
||||
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
int recv_testcase(int s, void **buf, size_t *max_len) {
|
||||
|
||||
u32 size;
|
||||
s32 ret;
|
||||
size_t received;
|
||||
|
||||
received = 0;
|
||||
while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != 4) FATAL("did not receive size information");
|
||||
if (size == 0) FATAL("did not receive valid size information");
|
||||
// fprintf(stderr, "received size information of %d\n", size);
|
||||
|
||||
if ((size & 0xff000000) != 0xff000000) {
|
||||
|
||||
*buf = ck_maybe_grow(buf, max_len, size);
|
||||
received = 0;
|
||||
// fprintf(stderr, "unCOMPRESS (%u)\n", size);
|
||||
while (received < size &&
|
||||
(ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0)
|
||||
received += ret;
|
||||
|
||||
} else {
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
u32 clen;
|
||||
size -= 0xff000000;
|
||||
*buf = ck_maybe_grow(buf, max_len, size);
|
||||
received = 0;
|
||||
while (received < 4 &&
|
||||
(ret = recv(s, &clen + received, 4 - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != 4) FATAL("did not receive clen1 information");
|
||||
// fprintf(stderr, "received clen information of %d\n", clen);
|
||||
if (clen < 1)
|
||||
FATAL("did not receive valid compressed len information: %u", clen);
|
||||
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, clen);
|
||||
received = 0;
|
||||
while (received < clen &&
|
||||
(ret = recv(s, buf2 + received, clen - received, 0)) > 0)
|
||||
received += ret;
|
||||
if (received != clen) FATAL("did not receive compressed information");
|
||||
if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf,
|
||||
*max_len,
|
||||
&received) != LIBDEFLATE_SUCCESS)
|
||||
FATAL("decompression failed");
|
||||
// fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received);
|
||||
// for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]);
|
||||
// fprintf(stderr, "\n");
|
||||
// for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x",
|
||||
// ((u8*)(*buf))[i]); fprintf(stderr, "\n");
|
||||
#else
|
||||
FATAL("Received compressed data but not compiled with compression support");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len);
|
||||
if (received != size)
|
||||
FATAL("did not receive testcase data %lu != %u, %d", received, size, ret);
|
||||
// fprintf(stderr, "received testcase\n");
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
s32 opt, s, sock, on = 1, port = -1;
|
||||
size_t max_len = 0;
|
||||
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
|
||||
char **use_argv;
|
||||
struct sockaddr_in6 serveraddr, clientaddr;
|
||||
int addrlen = sizeof(clientaddr);
|
||||
char str[INET6_ADDRSTRLEN];
|
||||
char ** argv = argv_cpy_dup(argc, argv_orig);
|
||||
u8 * send_buf;
|
||||
#ifdef USE_DEFLATE
|
||||
u32 *lenptr;
|
||||
#endif
|
||||
|
||||
afl_forkserver_t fsrv_var = {0};
|
||||
afl_forkserver_t *fsrv = &fsrv_var;
|
||||
afl_fsrv_init(fsrv);
|
||||
map_size = get_map_size();
|
||||
fsrv->map_size = map_size;
|
||||
|
||||
if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc");
|
||||
|
||||
while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'i':
|
||||
|
||||
if (port > 0) { FATAL("Multiple -i options not supported"); }
|
||||
port = atoi(optarg);
|
||||
if (port < 1 || port > 65535)
|
||||
FATAL("invalid port definition, must be between 1-65535: %s", optarg);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
|
||||
if (out_file) { FATAL("Multiple -f options not supported"); }
|
||||
fsrv->use_stdin = 0;
|
||||
out_file = optarg;
|
||||
break;
|
||||
|
||||
case 'm': {
|
||||
|
||||
u8 suffix = 'M';
|
||||
|
||||
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
|
||||
mem_limit_given = 1;
|
||||
|
||||
if (!optarg) { FATAL("Wrong usage of -m"); }
|
||||
|
||||
if (!strcmp(optarg, "none")) {
|
||||
|
||||
fsrv->mem_limit = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
|
||||
optarg[0] == '-') {
|
||||
|
||||
FATAL("Bad syntax used for -m");
|
||||
|
||||
}
|
||||
|
||||
switch (suffix) {
|
||||
|
||||
case 'T':
|
||||
fsrv->mem_limit *= 1024 * 1024;
|
||||
break;
|
||||
case 'G':
|
||||
fsrv->mem_limit *= 1024;
|
||||
break;
|
||||
case 'k':
|
||||
fsrv->mem_limit /= 1024;
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
|
||||
default:
|
||||
FATAL("Unsupported suffix or bad syntax for -m");
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
|
||||
|
||||
if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
|
||||
|
||||
FATAL("Value of -m out of range on 32-bit systems");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 't':
|
||||
|
||||
if (timeout_given) { FATAL("Multiple -t options not supported"); }
|
||||
timeout_given = 1;
|
||||
|
||||
if (!optarg) { FATAL("Wrong usage of -t"); }
|
||||
|
||||
fsrv->exec_tmout = atoi(optarg);
|
||||
|
||||
if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
|
||||
|
||||
FATAL("Dangerously low value of -t");
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
|
||||
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
|
||||
|
||||
fsrv->qemu_mode = 1;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
|
||||
if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
|
||||
|
||||
unicorn_mode = 1;
|
||||
break;
|
||||
|
||||
case 'W': /* Wine+QEMU mode */
|
||||
|
||||
if (use_wine) { FATAL("Multiple -W options not supported"); }
|
||||
fsrv->qemu_mode = 1;
|
||||
use_wine = 1;
|
||||
|
||||
if (!mem_limit_given) { fsrv->mem_limit = 0; }
|
||||
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(argv[0]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (optind == argc || port < 1) { usage(argv[0]); }
|
||||
|
||||
check_environment_vars(envp);
|
||||
|
||||
sharedmem_t shm = {0};
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
|
||||
in_data = ck_maybe_grow((void **)&in_data, &max_len, 65536);
|
||||
|
||||
atexit(at_exit_handler);
|
||||
setup_signal_handlers();
|
||||
|
||||
set_up_environment(fsrv);
|
||||
|
||||
fsrv->target_path = find_binary(argv[optind]);
|
||||
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
if (use_wine) {
|
||||
|
||||
use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
|
||||
argv + optind);
|
||||
|
||||
} else {
|
||||
|
||||
use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
|
||||
argv + optind);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
use_argv = argv + optind;
|
||||
|
||||
}
|
||||
|
||||
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed");
|
||||
|
||||
#ifdef SO_REUSEADDR
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
|
||||
|
||||
WARNF("setsockopt(SO_REUSEADDR) failed");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
int priority = 7;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
|
||||
0) {
|
||||
|
||||
priority = 6;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
|
||||
0)
|
||||
WARNF("could not set priority on socket");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin6_family = AF_INET6;
|
||||
serveraddr.sin6_port = htons(port);
|
||||
serveraddr.sin6_addr = in6addr_any;
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
PFATAL("bind() failed");
|
||||
|
||||
if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
|
||||
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
compressor = libdeflate_alloc_compressor(1);
|
||||
decompressor = libdeflate_alloc_decompressor();
|
||||
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, map_size + 16);
|
||||
lenptr = (u32 *)(buf2 + 4);
|
||||
fprintf(stderr, "Compiled with compression support\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr,
|
||||
"Waiting for incoming connection from afl-network-client on port %d "
|
||||
"...\n",
|
||||
port);
|
||||
|
||||
if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); }
|
||||
fprintf(stderr, "Received connection, starting ...\n");
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
priority = 7;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) {
|
||||
|
||||
priority = 6;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
|
||||
WARNF("could not set priority on socket");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) {
|
||||
|
||||
// fprintf(stderr, "received %u\n", in_len);
|
||||
(void)run_target(fsrv, use_argv, in_data, in_len, 1);
|
||||
|
||||
memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size);
|
||||
|
||||
#ifdef USE_DEFLATE
|
||||
memcpy(buf2, &fsrv->child_status, 4);
|
||||
*lenptr = (u32)libdeflate_deflate_compress(
|
||||
compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8);
|
||||
// fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr);
|
||||
// for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x",
|
||||
// fsrv->trace_bits[i]); fprintf(stderr, "\n");
|
||||
if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr)
|
||||
FATAL("could not send data");
|
||||
#else
|
||||
memcpy(send_buf, &fsrv->child_status, 4);
|
||||
if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size)
|
||||
FATAL("could not send data");
|
||||
#endif
|
||||
|
||||
// fprintf(stderr, "sent result\n");
|
||||
|
||||
}
|
||||
|
||||
unlink(out_file);
|
||||
if (out_file) { ck_free(out_file); }
|
||||
out_file = NULL;
|
||||
|
||||
afl_shm_deinit(&shm);
|
||||
afl_fsrv_deinit(fsrv);
|
||||
if (fsrv->target_path) { ck_free(fsrv->target_path); }
|
||||
if (in_data) { ck_free(in_data); }
|
||||
#if USE_DEFLATE
|
||||
if (buf2) { ck_free(buf2); }
|
||||
libdeflate_free_compressor(compressor);
|
||||
libdeflate_free_decompressor(decompressor);
|
||||
#endif
|
||||
|
||||
argv_cpy_free(argv);
|
||||
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
7
examples/afl_proxy/Makefile
Normal file
7
examples/afl_proxy/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: afl-proxy
|
||||
|
||||
afl-proxy: afl-proxy.c
|
||||
$(CC) -I../../include -o afl-proxy afl-proxy.c
|
||||
|
||||
clean:
|
||||
rm -f afl-proxy *~ core
|
9
examples/afl_proxy/README.md
Normal file
9
examples/afl_proxy/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# afl-proxy
|
||||
|
||||
afl-proxy is an example skeleton file which can easily be used to fuzz
|
||||
and instrument non-standard things.
|
||||
|
||||
You only need to change the while() loop of the main() to send the
|
||||
data of buf[] with length len to the target and write the coverage
|
||||
information to __afl_area_ptr[__afl_map_size]
|
||||
|
238
examples/afl_proxy/afl-proxy.c
Normal file
238
examples/afl_proxy/afl-proxy.c
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
american fuzzy lop++ - afl-proxy skeleton example
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de>
|
||||
|
||||
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
|
||||
|
||||
|
||||
HOW-TO
|
||||
======
|
||||
|
||||
You only need to change the while() loop of the main() to send the
|
||||
data of buf[] with length len to the target and write the coverage
|
||||
information to __afl_area_ptr[__afl_map_size]
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
u8 *__afl_area_ptr;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_map_size = MAP_SIZE;
|
||||
#else
|
||||
__thread u32 __afl_map_size = MAP_SIZE;
|
||||
#endif
|
||||
|
||||
/* Error reporting to forkserver controller */
|
||||
|
||||
void send_forkserver_error(int error) {
|
||||
|
||||
u32 status;
|
||||
if (!error || error > 0xffff) return;
|
||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
|
||||
|
||||
}
|
||||
|
||||
/* SHM setup. */
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
char *ptr;
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
|
||||
|
||||
u32 val = atoi(ptr);
|
||||
if (val > 0) __afl_map_size = val;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_map_size > MAP_SIZE) {
|
||||
|
||||
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
if (id_str) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr,
|
||||
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
unsigned char *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* map the shared memory segment to the address space of the process */
|
||||
shm_base =
|
||||
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
if (shm_base == MAP_FAILED) {
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
send_forkserver_error(FS_ERROR_MMAP);
|
||||
exit(2);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = shm_base;
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, 0, 0);
|
||||
|
||||
#endif
|
||||
|
||||
if (__afl_area_ptr == (void *)-1) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_SHMAT);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* Write something into the bitmap so that the parent doesn't give up */
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic. */
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 status = 0;
|
||||
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
|
||||
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
if (status) status |= (FS_OPT_ENABLED);
|
||||
memcpy(tmp, &status, 4);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
|
||||
}
|
||||
|
||||
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
|
||||
s32 status, res = 0xffffff;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
if (read(FORKSRV_FD, &status, 4) != 4) return 0;
|
||||
|
||||
/* we have a testcase - read it */
|
||||
status = read(0, buf, max_len);
|
||||
|
||||
/* report that we are starting the target */
|
||||
if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
|
||||
|
||||
if (status < 1)
|
||||
return 0;
|
||||
else
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static void __afl_end_testcase(void) {
|
||||
|
||||
int status = 0xffffff;
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* you just need to modify the while() loop in this main() */
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
/* This is were the testcase data is written into */
|
||||
u8 buf[1024]; // this is the maximum size for a test case! set it!
|
||||
u32 len;
|
||||
|
||||
/* here you specify the map size you need that you are reporting to
|
||||
afl-fuzz. */
|
||||
__afl_map_size = MAP_SIZE; // default is 65536
|
||||
|
||||
/* then we initialize the shared memory map and start the forkserver */
|
||||
__afl_map_shm();
|
||||
__afl_start_forkserver();
|
||||
|
||||
while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
|
||||
|
||||
/* here you have to create the magic that feeds the buf/len to the
|
||||
target and write the coverage to __afl_area_ptr */
|
||||
|
||||
// ... the magic ...
|
||||
|
||||
/* report the test case is done and wait for the next */
|
||||
__afl_end_testcase();
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
16
examples/afl_untracer/Makefile
Normal file
16
examples/afl_untracer/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
ifdef DEBUG
|
||||
OPT=-O0
|
||||
else
|
||||
OPT=-O3
|
||||
endif
|
||||
|
||||
all: afl-untracer libtestinstr.so
|
||||
|
||||
afl-untracer: afl-untracer.c
|
||||
$(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl
|
||||
|
||||
libtestinstr.so: libtestinstr.c
|
||||
$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
|
||||
|
||||
clean:
|
||||
rm -f afl-untracer libtestinstr.so *~ core
|
59
examples/afl_untracer/README.md
Normal file
59
examples/afl_untracer/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
# afl-untracer - fast fuzzing of binary-only libraries
|
||||
|
||||
## Introduction
|
||||
|
||||
afl-untracer is an example skeleton file which can easily be used to fuzz
|
||||
a closed source library.
|
||||
|
||||
It requires less memory and is x3-5 faster than qemu_mode however it is way
|
||||
more course grained and does not provide interesting features like compcov
|
||||
or cmplog.
|
||||
|
||||
Supported is so far Intel (i386/x86_64) and AARCH64.
|
||||
|
||||
## How-to
|
||||
|
||||
### Modify afl-untracer.c
|
||||
|
||||
Read and modify afl-untracer.c then `make`.
|
||||
To adapt afl-untracer.c to your needs, read the header of the file and then
|
||||
search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
|
||||
|
||||
### Generate patches.txt file
|
||||
|
||||
To generate the `patches.txt` file for your target library use the
|
||||
`ida_get_patchpoints.py` script for IDA Pro or
|
||||
`ghidra_get_patchpoints.java` for Ghidra.
|
||||
|
||||
The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`.
|
||||
|
||||
To easily run the scripts without needing to run the GUI with Ghidra:
|
||||
```
|
||||
$ /opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
|
||||
$ rm -rf /tmp/tmp$$
|
||||
```
|
||||
|
||||
### Fuzzing
|
||||
|
||||
Example (after modifying afl-untracer.c to your needs, compiling and creating
|
||||
patches.txt):
|
||||
```
|
||||
AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
|
||||
```
|
||||
(or even remote via afl-network-proxy).
|
||||
|
||||
### Testing and debugging
|
||||
|
||||
For testing/debugging you can try:
|
||||
```
|
||||
make DEBUG=1
|
||||
AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer
|
||||
```
|
||||
and then you can easily set breakpoints to "breakpoint" and "fuzz".
|
||||
|
||||
# Background
|
||||
|
||||
This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
|
||||
and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
|
||||
This implementation is slower because the traps are not patched out with each
|
||||
run, but on the other hand gives much better coverage information.
|
756
examples/afl_untracer/afl-untracer.c
Normal file
756
examples/afl_untracer/afl-untracer.c
Normal file
@ -0,0 +1,756 @@
|
||||
/*
|
||||
american fuzzy lop++ - afl-untracer skeleton example
|
||||
---------------------------------------------------
|
||||
|
||||
Written by Marc Heuse <mh@mh-sec.de>
|
||||
|
||||
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
|
||||
|
||||
|
||||
HOW-TO
|
||||
======
|
||||
|
||||
You only need to change the following:
|
||||
|
||||
1. decide if you want to receive data from stdin [DEFAULT] or file(name)
|
||||
-> use_stdin = 0 if via file, and what the maximum input size is
|
||||
2. dl load the library you want to fuzz, lookup the functions you need
|
||||
and setup the calls to these
|
||||
3. in the while loop you call the functions in the necessary order -
|
||||
incl the cleanup. the cleanup is important!
|
||||
|
||||
Just look these steps up in the code, look for "// STEP x:"
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define __USE_GNU
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/ucontext.h>
|
||||
#elif defined(__APPLE__) && defined(__LP64__)
|
||||
#include <mach-o/dyld_images.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
#define MEMORY_MAP_DECREMENT 0x200000000000
|
||||
#define MAX_LIB_COUNT 128
|
||||
|
||||
// STEP 1:
|
||||
|
||||
/* use stdin (1) or a file on the commandline (0) */
|
||||
static u32 use_stdin = 1;
|
||||
|
||||
/* This is were the testcase data is written into */
|
||||
static u8 buf[10000]; // this is the maximum size for a test case! set it!
|
||||
|
||||
/* If you want to have debug output set this to 1, can also be set with
|
||||
AFL_DEBUG */
|
||||
static u32 debug = 0;
|
||||
|
||||
// END STEP 1
|
||||
|
||||
typedef struct library_list {
|
||||
|
||||
u8 *name;
|
||||
u64 addr_start, addr_end;
|
||||
|
||||
} library_list_t;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_map_size = MAP_SIZE;
|
||||
u32 do_exit;
|
||||
#else
|
||||
__thread u32 __afl_map_size = MAP_SIZE;
|
||||
__thread u32 do_exit;
|
||||
#endif
|
||||
|
||||
static pid_t pid = 65537;
|
||||
static pthread_t __afl_thread;
|
||||
static u8 __afl_dummy[MAP_SIZE];
|
||||
static u8 * __afl_area_ptr = __afl_dummy;
|
||||
static u8 * inputfile; // this will point to argv[1]
|
||||
static u32 len;
|
||||
|
||||
static library_list_t liblist[MAX_LIB_COUNT];
|
||||
static u32 liblist_cnt;
|
||||
|
||||
static void sigtrap_handler(int signum, siginfo_t *si, void *context);
|
||||
static void fuzz();
|
||||
|
||||
/* read the library information */
|
||||
void read_library_information() {
|
||||
|
||||
#if defined(__linux__)
|
||||
FILE *f;
|
||||
u8 buf[1024], *b, *m, *e, *n;
|
||||
|
||||
if ((f = fopen("/proc/self/maps", "r")) == NULL)
|
||||
FATAL("cannot open /proc/self/maps");
|
||||
|
||||
if (debug) fprintf(stderr, "Library list:\n");
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
|
||||
if (strstr(buf, " r-x")) {
|
||||
|
||||
if (liblist_cnt >= MAX_LIB_COUNT) {
|
||||
|
||||
WARNF("too many libraries to old, maximum count of %d reached",
|
||||
liblist_cnt);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
b = buf;
|
||||
m = index(buf, '-');
|
||||
e = index(buf, ' ');
|
||||
if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' ');
|
||||
if (n &&
|
||||
((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
|
||||
n = NULL;
|
||||
else
|
||||
n++;
|
||||
if (b && m && e && n && *n) {
|
||||
|
||||
*m++ = 0;
|
||||
*e = 0;
|
||||
if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
|
||||
|
||||
liblist[liblist_cnt].name = strdup(n);
|
||||
liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
|
||||
liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
|
||||
if (debug)
|
||||
fprintf(
|
||||
stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
|
||||
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_end - 1);
|
||||
liblist_cnt++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (debug) fprintf(stderr, "\n");
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
|
||||
char * buf, *start, *end;
|
||||
size_t miblen = sizeof(mib) / sizeof(mib[0]);
|
||||
size_t len;
|
||||
|
||||
if (debug) fprintf(stderr, "Library list:\n");
|
||||
if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
|
||||
|
||||
len = len * 4 / 3;
|
||||
|
||||
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (buf == MAP_FAILED) { return; }
|
||||
|
||||
if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
|
||||
|
||||
munmap(buf, len);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
start = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (start < end) {
|
||||
|
||||
struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
|
||||
size_t size = region->kve_structsize;
|
||||
|
||||
if (size == 0) { break; }
|
||||
|
||||
if ((region->kve_protection & KVME_PROT_READ) &&
|
||||
!(region->kve_protection & KVME_PROT_EXEC)) {
|
||||
|
||||
liblist[liblist_cnt].name =
|
||||
region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
|
||||
liblist[liblist_cnt].addr_start = region->kve_start;
|
||||
liblist[liblist_cnt].addr_end = region->kve_end;
|
||||
|
||||
if (debug) {
|
||||
|
||||
fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
|
||||
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_start,
|
||||
liblist[liblist_cnt].addr_end - 1);
|
||||
|
||||
}
|
||||
|
||||
liblist_cnt++;
|
||||
|
||||
}
|
||||
|
||||
start += size;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
library_list_t *find_library(char *name) {
|
||||
|
||||
#if defined(__linux__)
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < liblist_cnt; i++)
|
||||
if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
|
||||
#elif defined(__APPLE__) && defined(__LP64__)
|
||||
kern_return_t err;
|
||||
static library_list_t lib;
|
||||
|
||||
// get the list of all loaded modules from dyld
|
||||
// the task_info mach API will get the address of the dyld all_image_info
|
||||
// struct for the given task from which we can get the names and load
|
||||
// addresses of all modules
|
||||
task_dyld_info_data_t task_dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
err = task_info(mach_task_self(), TASK_DYLD_INFO,
|
||||
(task_info_t)&task_dyld_info, &count);
|
||||
|
||||
const struct dyld_all_image_infos *all_image_infos =
|
||||
(const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
|
||||
const struct dyld_image_info *image_infos = all_image_infos->infoArray;
|
||||
|
||||
for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
|
||||
|
||||
const char * image_name = image_infos[i].imageFilePath;
|
||||
mach_vm_address_t image_load_address =
|
||||
(mach_vm_address_t)image_infos[i].imageLoadAddress;
|
||||
if (strstr(image_name, name)) {
|
||||
|
||||
lib.name = name;
|
||||
lib.addr_start = (u64)image_load_address;
|
||||
lib.addr_end = 0;
|
||||
return &lib;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* for having an easy breakpoint location after loading the shared library */
|
||||
// this seems to work for clang too. nice :) requires gcc 4.4+
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
void breakpoint() {
|
||||
|
||||
if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
/* Error reporting to forkserver controller */
|
||||
|
||||
void send_forkserver_error(int error) {
|
||||
|
||||
u32 status;
|
||||
if (!error || error > 0xffff) return;
|
||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
|
||||
|
||||
}
|
||||
|
||||
/* SHM setup. */
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
char *ptr;
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
|
||||
|
||||
u32 val = atoi(ptr);
|
||||
if (val > 0) __afl_map_size = val;
|
||||
|
||||
}
|
||||
|
||||
if (__afl_map_size > MAP_SIZE) {
|
||||
|
||||
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
if (id_str) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_MAP_SIZE);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr,
|
||||
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
|
||||
"be able to run this instrumented program!\n",
|
||||
__afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
unsigned char *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* map the shared memory segment to the address space of the process */
|
||||
shm_base =
|
||||
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
if (shm_base == MAP_FAILED) {
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
send_forkserver_error(FS_ERROR_MMAP);
|
||||
exit(2);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = shm_base;
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
__afl_area_ptr = shmat(shm_id, 0, 0);
|
||||
|
||||
#endif
|
||||
|
||||
if (__afl_area_ptr == (void *)-1) {
|
||||
|
||||
send_forkserver_error(FS_ERROR_SHMAT);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* Write something into the bitmap so that the parent doesn't give up */
|
||||
|
||||
__afl_area_ptr[0] = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic. */
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 status = 0;
|
||||
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
|
||||
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
if (status) status |= (FS_OPT_ENABLED);
|
||||
memcpy(tmp, &status, 4);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. */
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "write0 %d\n", do_exit);
|
||||
|
||||
}
|
||||
|
||||
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
|
||||
s32 status;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "read %d\n", do_exit);
|
||||
|
||||
/* we have a testcase - read it if we read from stdin */
|
||||
if (use_stdin) {
|
||||
|
||||
if ((status = read(0, buf, max_len)) <= 0) exit(-1);
|
||||
|
||||
} else
|
||||
|
||||
status = 1;
|
||||
// fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
|
||||
|
||||
/* report that we are starting the target */
|
||||
if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "write1 %d\n", do_exit);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static void __afl_end_testcase(int status) {
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
|
||||
// fprintf(stderr, "write2 %d\n", do_exit);
|
||||
if (do_exit) exit(0);
|
||||
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define SHADOW(addr) \
|
||||
((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
|
||||
MEMORY_MAP_DECREMENT - \
|
||||
((uintptr_t)addr & 0x7) * 0x10000000000))
|
||||
#else
|
||||
#define SHADOW(addr) \
|
||||
((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
|
||||
MEMORY_MAP_DECREMENT - \
|
||||
((uintptr_t)addr & 0x3) * 0x10000000000))
|
||||
#endif
|
||||
|
||||
void setup_trap_instrumentation() {
|
||||
|
||||
library_list_t *lib_base = NULL;
|
||||
size_t lib_size = 0;
|
||||
u8 * lib_addr;
|
||||
char * line = NULL;
|
||||
size_t nread, len = 0;
|
||||
char * filename = getenv("AFL_UNTRACER_FILE");
|
||||
if (!filename) filename = getenv("TRAPFUZZ_FILE");
|
||||
if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
|
||||
|
||||
FILE *patches = fopen(filename, "r");
|
||||
if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
|
||||
|
||||
// Index into the coverage bitmap for the current trap instruction.
|
||||
#ifdef __aarch64__
|
||||
uint64_t bitmap_index = 0;
|
||||
#else
|
||||
uint32_t bitmap_index = 0;
|
||||
#endif
|
||||
|
||||
while ((nread = getline(&line, &len, patches)) != -1) {
|
||||
|
||||
char *end = line + len;
|
||||
|
||||
char *col = strchr(line, ':');
|
||||
if (col) {
|
||||
|
||||
// It's a library:size pair
|
||||
*col++ = 0;
|
||||
|
||||
lib_base = find_library(line);
|
||||
if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
|
||||
|
||||
// we ignore the defined lib_size
|
||||
lib_size = strtoul(col, NULL, 16);
|
||||
#if (__linux__)
|
||||
if (lib_size < lib_base->addr_end - lib_base->addr_start)
|
||||
lib_size = lib_base->addr_end - lib_base->addr_start;
|
||||
#endif
|
||||
if (lib_size % 0x1000 != 0)
|
||||
WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
|
||||
lib_size);
|
||||
|
||||
lib_addr = (u8 *)lib_base->addr_start;
|
||||
|
||||
// Make library code writable.
|
||||
if (mprotect((void *)lib_addr, lib_size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
||||
FATAL("Failed to mprotect library %s writable", line);
|
||||
|
||||
// Create shadow memory.
|
||||
#ifdef __aarch64__
|
||||
for (int i = 0; i < 8; i++) {
|
||||
|
||||
#else
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
||||
#endif
|
||||
|
||||
void *shadow_addr = SHADOW(lib_addr + i);
|
||||
void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
|
||||
if (debug)
|
||||
fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
|
||||
shadow + lib_size - 1, lib_addr);
|
||||
if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
|
||||
|
||||
}
|
||||
|
||||
// Done, continue with next line.
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// It's an offset, parse it and do the patching.
|
||||
unsigned long offset = strtoul(line, NULL, 16);
|
||||
|
||||
if (offset > lib_size)
|
||||
FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
|
||||
offset, lib_size);
|
||||
|
||||
if (bitmap_index >= __afl_map_size)
|
||||
FATAL("Too many basic blocks to instrument");
|
||||
|
||||
#ifdef __arch64__
|
||||
uint64_t
|
||||
#else
|
||||
uint32_t
|
||||
#endif
|
||||
*shadow = SHADOW(lib_addr + offset);
|
||||
if (*shadow != 0) continue; // skip duplicates
|
||||
|
||||
// Make lookup entry in shadow memory.
|
||||
|
||||
#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
|
||||
defined(__i386__))
|
||||
|
||||
// this is for Intel x64
|
||||
|
||||
uint8_t orig_byte = lib_addr[offset];
|
||||
*shadow = (bitmap_index << 8) | orig_byte;
|
||||
lib_addr[offset] = 0xcc; // replace instruction with debug trap
|
||||
if (debug)
|
||||
fprintf(stderr,
|
||||
"Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
|
||||
lib_addr, offset, lib_addr + offset, orig_byte, shadow,
|
||||
bitmap_index, *shadow);
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
// this is for aarch64
|
||||
|
||||
uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
|
||||
uint32_t orig_bytes = *patch_bytes;
|
||||
*shadow = (bitmap_index << 32) | orig_bytes;
|
||||
*patch_bytes = 0xd4200000; // replace instruction with debug trap
|
||||
if (debug)
|
||||
fprintf(stderr,
|
||||
"Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
|
||||
lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
|
||||
bitmap_index, *shadow);
|
||||
|
||||
#else
|
||||
// this will be ARM and AARCH64
|
||||
// for ARM we will need to identify if the code is in thumb or ARM
|
||||
#error "non x86_64/aarch64 not supported yet"
|
||||
//__arm__:
|
||||
// linux thumb: 0xde01
|
||||
// linux arm: 0xe7f001f0
|
||||
//__aarch64__:
|
||||
// linux aarch64: 0xd4200000
|
||||
#endif
|
||||
|
||||
bitmap_index++;
|
||||
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(patches);
|
||||
|
||||
// Install signal handler for SIGTRAP.
|
||||
struct sigaction s;
|
||||
s.sa_flags = SA_SIGINFO;
|
||||
s.sa_sigaction = sigtrap_handler;
|
||||
sigemptyset(&s.sa_mask);
|
||||
sigaction(SIGTRAP, &s, 0);
|
||||
|
||||
if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
|
||||
__afl_map_size = bitmap_index;
|
||||
if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
|
||||
|
||||
}
|
||||
|
||||
/* the signal handler for the traps / debugging interrupts
|
||||
No debug output here because this would cost speed */
|
||||
static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
|
||||
|
||||
uint64_t addr;
|
||||
// Must re-execute the instruction, so decrement PC by one instruction.
|
||||
ucontext_t *ctx = (ucontext_t *)context;
|
||||
#if defined(__APPLE__) && defined(__LP64__)
|
||||
ctx->uc_mcontext->__ss.__rip -= 1;
|
||||
addr = ctx->uc_mcontext->__ss.__rip;
|
||||
#elif defined(__linux__)
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
ctx->uc_mcontext.gregs[REG_RIP] -= 1;
|
||||
addr = ctx->uc_mcontext.gregs[REG_RIP];
|
||||
#elif defined(__aarch64__)
|
||||
ctx->uc_mcontext.pc -= 4;
|
||||
addr = ctx->uc_mcontext.pc;
|
||||
#else
|
||||
#error "Unsupported processor"
|
||||
#endif
|
||||
#elif defined(__FreeBSD__) && defined(__LP64__)
|
||||
ctx->uc_mcontext.mc_rip -= 1;
|
||||
addr = ctx->uc_mcontext.mc_rip;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
// fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
|
||||
// si->si_addr);
|
||||
|
||||
// If the trap didn't come from our instrumentation, then we probably will
|
||||
// just segfault here
|
||||
uint8_t *faultaddr;
|
||||
if (unlikely(si->si_addr))
|
||||
faultaddr = (u8 *)si->si_addr - 1;
|
||||
else
|
||||
faultaddr = (u8 *)addr;
|
||||
// if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
|
||||
uint32_t shadow = *SHADOW(faultaddr);
|
||||
uint8_t orig_byte = shadow & 0xff;
|
||||
uint32_t index = shadow >> 8;
|
||||
|
||||
// if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
|
||||
// shadow, orig_byte, index);
|
||||
|
||||
// Index zero is invalid so that it is still possible to catch actual trap
|
||||
// instructions in instrumented libraries.
|
||||
if (unlikely(index == 0)) abort();
|
||||
|
||||
// Restore original instruction
|
||||
*faultaddr = orig_byte;
|
||||
|
||||
__afl_area_ptr[index] = 128;
|
||||
|
||||
}
|
||||
|
||||
/* here you need to specify the parameter for the target function */
|
||||
static void *(*o_function)(u8 *buf, int len);
|
||||
|
||||
/* the MAIN function */
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
pid = getpid();
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
/* by default we use stdin, but also a filename can be passed, in this
|
||||
case the input is argv[1] and we have to disable stdin */
|
||||
if (argc > 1) {
|
||||
|
||||
use_stdin = 0;
|
||||
inputfile = argv[1];
|
||||
|
||||
}
|
||||
|
||||
// STEP 2: load the library you want to fuzz and lookup the functions,
|
||||
// inclusive of the cleanup functions
|
||||
// NOTE: above the main() you have to define the functions!
|
||||
|
||||
void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
|
||||
if (!dl) FATAL("could not find target library");
|
||||
o_function = dlsym(dl, "testinstr");
|
||||
if (!o_function) FATAL("could not resolve target function from library");
|
||||
if (debug) fprintf(stderr, "Function address: %p\n", o_function);
|
||||
|
||||
// END STEP 2
|
||||
|
||||
/* setup instrumentation, shared memory and forkserver */
|
||||
breakpoint();
|
||||
read_library_information();
|
||||
setup_trap_instrumentation();
|
||||
__afl_map_shm();
|
||||
__afl_start_forkserver();
|
||||
|
||||
while (1) {
|
||||
|
||||
if ((pid = fork()) == -1) PFATAL("fork failed");
|
||||
|
||||
if (pid) {
|
||||
|
||||
u32 status;
|
||||
if (waitpid(pid, &status, 0) < 0) exit(1);
|
||||
/* report the test case is done and wait for the next */
|
||||
__afl_end_testcase(status);
|
||||
|
||||
} else {
|
||||
|
||||
pid = getpid();
|
||||
while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
|
||||
|
||||
// in this function the fuzz magic happens, this is STEP 3
|
||||
fuzz();
|
||||
|
||||
// we can use _exit which is faster because our target library
|
||||
// was loaded via dlopen and therefore cannot have deconstructors
|
||||
// registered.
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void fuzz() {
|
||||
|
||||
// STEP 3: call the function to fuzz, also the functions you might
|
||||
// need to call to prepare the function and - important! -
|
||||
// to clean everything up
|
||||
|
||||
// in this example we use the input file, not stdin!
|
||||
(*o_function)(buf, len);
|
||||
|
||||
// normally you also need to cleanup
|
||||
//(*o_LibFree)(foo);
|
||||
|
||||
// END STEP 3
|
||||
|
||||
}
|
||||
|
84
examples/afl_untracer/ghidra_get_patchpoints.java
Normal file
84
examples/afl_untracer/ghidra_get_patchpoints.java
Normal file
@ -0,0 +1,84 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer)
|
||||
//
|
||||
// Copy to ..../Ghidra/Features/Search/ghidra_scripts/
|
||||
// Writes the results to ~/Desktop/patches.txt
|
||||
//
|
||||
// This is my very first Ghidra script. I am sure this could be done better.
|
||||
//
|
||||
//@category Search
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.block.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ghidra_get_patchpoints extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
|
||||
long segment_start = 0;
|
||||
Memory memory = currentProgram.getMemory();
|
||||
MultEntSubModel model = new MultEntSubModel(currentProgram);
|
||||
CodeBlockIterator subIter = model.getCodeBlocks(monitor);
|
||||
BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt"));
|
||||
|
||||
while (subIter.hasNext()) {
|
||||
|
||||
CodeBlock multiEntryBlock = subIter.next();
|
||||
SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram);
|
||||
CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor);
|
||||
|
||||
while (bbIter.hasNext()) {
|
||||
|
||||
CodeBlock basicBlock = bbIter.next();
|
||||
|
||||
if (segment_start == 0) {
|
||||
|
||||
Address firstAddr = basicBlock.getFirstStartAddress();
|
||||
long firstBlockAddr = firstAddr.getAddressableWordOffset();
|
||||
MemoryBlock mb = memory.getBlock(firstAddr);
|
||||
Address startAddr = mb.getStart();
|
||||
Address endAddr = mb.getEnd();
|
||||
segment_start = startAddr.getAddressableWordOffset();
|
||||
if ((firstBlockAddr - segment_start) >= 0x1000)
|
||||
segment_start += 0x1000;
|
||||
long segment_end = endAddr.getAddressableWordOffset();
|
||||
long segment_size = segment_end - segment_start;
|
||||
if ((segment_size % 0x1000) > 0)
|
||||
segment_size = (((segment_size / 0x1000) + 1) * 0x1000);
|
||||
out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n");
|
||||
//println("Start: " + Long.toHexString(segment_start));
|
||||
//println("End: " + Long.toHexString(segment_end));
|
||||
|
||||
}
|
||||
|
||||
if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0)
|
||||
out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
}
|
||||
}
|
62
examples/afl_untracer/ida_get_patchpoints.py
Normal file
62
examples/afl_untracer/ida_get_patchpoints.py
Normal file
@ -0,0 +1,62 @@
|
||||
#
|
||||
# IDAPython script for IDA Pro
|
||||
# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py
|
||||
#
|
||||
|
||||
import idautils
|
||||
import idaapi
|
||||
import ida_nalt
|
||||
import idc
|
||||
|
||||
# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
|
||||
|
||||
from os.path import expanduser
|
||||
home = expanduser("~")
|
||||
|
||||
patchpoints = set()
|
||||
|
||||
max_offset = 0
|
||||
for seg_ea in idautils.Segments():
|
||||
name = idc.get_segm_name(seg_ea)
|
||||
#print("Segment: " + name)
|
||||
if name != "__text" and name != ".text":
|
||||
continue
|
||||
|
||||
start = idc.get_segm_start(seg_ea)
|
||||
end = idc.get_segm_end(seg_ea)
|
||||
first = 0
|
||||
subtract_addr = 0
|
||||
#print("Start: " + hex(start) + " End: " + hex(end))
|
||||
for func_ea in idautils.Functions(start, end):
|
||||
f = idaapi.get_func(func_ea)
|
||||
if not f:
|
||||
continue
|
||||
for block in idaapi.FlowChart(f):
|
||||
if start <= block.start_ea < end:
|
||||
if first == 0:
|
||||
if block.start_ea >= 0x1000:
|
||||
subtract_addr = 0x1000
|
||||
first = 1
|
||||
|
||||
max_offset = max(max_offset, block.start_ea)
|
||||
patchpoints.add(block.start_ea - subtract_addr)
|
||||
#else:
|
||||
# print("Warning: broken CFG?")
|
||||
|
||||
# Round up max_offset to page size
|
||||
size = max_offset
|
||||
rem = size % 0x1000
|
||||
if rem != 0:
|
||||
size += 0x1000 - rem
|
||||
|
||||
print("Writing to " + home + "/Desktop/patches.txt")
|
||||
|
||||
with open(home + "/Desktop/patches.txt", "w") as f:
|
||||
f.write(ida_nalt.get_root_filename() + ':' + hex(size) + '\n')
|
||||
f.write('\n'.join(map(hex, sorted(patchpoints))))
|
||||
f.write('\n')
|
||||
|
||||
print("Done, found {} patchpoints".format(len(patchpoints)))
|
||||
|
||||
# For headless script running remove the comment from the next line
|
||||
#ida_pro.qexit()
|
35
examples/afl_untracer/libtestinstr.c
Normal file
35
examples/afl_untracer/libtestinstr.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
american fuzzy lop++ - a trivial program to test the build
|
||||
--------------------------------------------------------
|
||||
Originally written by Michal Zalewski
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
void testinstr(char *buf, int len) {
|
||||
|
||||
if (len < 1) return;
|
||||
buf[len] = 0;
|
||||
|
||||
// we support three input cases
|
||||
if (buf[0] == '0')
|
||||
printf("Looks like a zero to me!\n");
|
||||
else if (buf[0] == '1')
|
||||
printf("Pretty sure that is a one!\n");
|
||||
else
|
||||
printf("Neither one or zero? How quaint!\n");
|
||||
|
||||
}
|
||||
|
23
examples/afl_untracer/patches.txt
Normal file
23
examples/afl_untracer/patches.txt
Normal file
@ -0,0 +1,23 @@
|
||||
libtestinstr.so:0x2000L
|
||||
0x1050L
|
||||
0x1063L
|
||||
0x106fL
|
||||
0x1078L
|
||||
0x1080L
|
||||
0x10a4L
|
||||
0x10b0L
|
||||
0x10b8L
|
||||
0x10c0L
|
||||
0x10c9L
|
||||
0x10d7L
|
||||
0x10e3L
|
||||
0x10f8L
|
||||
0x1100L
|
||||
0x1105L
|
||||
0x111aL
|
||||
0x1135L
|
||||
0x1143L
|
||||
0x114eL
|
||||
0x115cL
|
||||
0x116aL
|
||||
0x116bL
|
@ -20,27 +20,34 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
CFLAGS = -fPIC -Wall -Wextra
|
||||
LDFLAGS = -shared
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
|
||||
UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
|
||||
|
||||
_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
# on gcc for arm there is no -m32, but -mbe32
|
||||
M32FLAG = -m32
|
||||
M64FLAG = -m64
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
M32FLAG = -mbe32
|
||||
endif
|
||||
endif
|
||||
|
||||
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
|
||||
CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
|
||||
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
|
||||
CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
|
||||
|
||||
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
|
||||
__M32FLAG=$(_M32FLAG:00=-mbe32)
|
||||
___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
|
||||
M32FLAG=$(___M32FLAG)
|
||||
|
||||
all: argvfuzz32.so argvfuzz64.so
|
||||
|
||||
argvfuzz32.so: argvfuzz.c
|
||||
-$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "argvfuzz32 build failure (that's fine)"
|
||||
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)"
|
||||
|
||||
argvfuzz64.so: argvfuzz.c
|
||||
-$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "argvfuzz64 build failure (that's fine)"
|
||||
-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)"
|
||||
|
||||
install: argvfuzz32.so argvfuzz64.so
|
||||
install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
|
||||
|
@ -55,12 +55,12 @@
|
||||
#define MAX_CMDLINE_LEN 100000
|
||||
#define MAX_CMDLINE_PAR 50000
|
||||
|
||||
static char** afl_init_argv(int* argc) {
|
||||
static char **afl_init_argv(int *argc) {
|
||||
|
||||
static char in_buf[MAX_CMDLINE_LEN];
|
||||
static char* ret[MAX_CMDLINE_PAR];
|
||||
static char *ret[MAX_CMDLINE_PAR];
|
||||
|
||||
char* ptr = in_buf;
|
||||
char *ptr = in_buf;
|
||||
int rc = 0;
|
||||
|
||||
if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {}
|
||||
|
@ -91,10 +91,10 @@ for crash in $DIR/crashes/id:*; do
|
||||
for a in $@; do
|
||||
|
||||
if [ "$a" = "@@" ] ; then
|
||||
args="$use_args $crash"
|
||||
use_args="$use_args $crash"
|
||||
unset use_stdio
|
||||
else
|
||||
args="$use_args $a"
|
||||
use_args="$use_args $a"
|
||||
fi
|
||||
|
||||
done
|
||||
|
7
examples/custom_mutators/Makefile
Normal file
7
examples/custom_mutators/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: libexamplemutator.so
|
||||
|
||||
libexamplemutator.so:
|
||||
$(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so
|
||||
|
||||
clean:
|
||||
rm -rf libexamplemutator.so
|
@ -1,2 +0,0 @@
|
||||
This is a simple example for the AFL_CUSTOM_MUTATOR_LIBRARY feature.
|
||||
For more information see [docs/custom_mutator.md](../docs/custom_mutator.md)
|
31
examples/custom_mutators/README.md
Normal file
31
examples/custom_mutators/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
# 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
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
||||
|
||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||
|
||||
XmlMutatorMin.py - module for XML mutation
|
||||
|
||||
custom_mutator_helpers.h is an header that defines some helper routines
|
||||
like surgical_havoc_mutate() that allow to perform a randomly chosen
|
||||
mutation from a subset of the havoc mutations.
|
||||
If you do so, you have to specify -I /path/to/AFLplusplus/include when
|
||||
compiling.
|
@ -7,6 +7,7 @@ from copy import deepcopy
|
||||
from lxml import etree as ET
|
||||
import random, re, io
|
||||
|
||||
|
||||
###########################
|
||||
# The XmlMutatorMin class #
|
||||
###########################
|
||||
@ -40,19 +41,19 @@ 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 +62,34 @@ 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)
|
||||
|
||||
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 +98,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 +120,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 +128,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,19 +145,19 @@ 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
|
||||
@ -236,29 +237,29 @@ class XmlMutatorMin:
|
||||
# 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) """
|
||||
|
||||
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) """
|
||||
|
||||
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:
|
||||
@ -275,12 +276,12 @@ class XmlMutatorMin:
|
||||
# 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):
|
||||
|
||||
def __del_content(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete the attributes and children of a random node """
|
||||
|
||||
@ -294,8 +295,8 @@ class XmlMutatorMin:
|
||||
# Reset the node
|
||||
rand_elem.clear()
|
||||
|
||||
def __del_attribute (self):
|
||||
|
||||
def __del_attribute(self):
|
||||
|
||||
""" High-level minimizing mutator
|
||||
Delete a random attribute from a random node """
|
||||
|
||||
@ -312,7 +313,7 @@ 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
|
||||
@ -322,8 +323,8 @@ class XmlMutatorMin:
|
||||
# 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
|
@ -19,19 +19,22 @@ 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))
|
||||
|
||||
|
||||
if not os.path.exists(exc_name):
|
||||
with open(exc_name, 'w') as f:
|
||||
f.write(data)
|
||||
f.write(data)
|
342
examples/custom_mutators/custom_mutator_helpers.h
Normal file
342
examples/custom_mutators/custom_mutator_helpers.h
Normal file
@ -0,0 +1,342 @@
|
||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
||||
#define CUSTOM_MUTATOR_HELPERS
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
#define RAND_BELOW(limit) (rand() % (limit))
|
||||
|
||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
||||
#define BUF_VAR(type, name) \
|
||||
type * name##_buf; \
|
||||
size_t name##_size;
|
||||
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
|
||||
#define BUF_PARAMS(struct, name) \
|
||||
(void **)&struct->name##_buf, &struct->name##_size
|
||||
|
||||
typedef struct {
|
||||
|
||||
} afl_t;
|
||||
|
||||
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
|
||||
|
||||
static s8 interesting_8[] = {INTERESTING_8};
|
||||
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
|
||||
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
|
||||
|
||||
switch (RAND_BELOW(12)) {
|
||||
|
||||
case 0: {
|
||||
|
||||
/* Flip a single bit somewhere. Spooky! */
|
||||
|
||||
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
|
||||
|
||||
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 1: {
|
||||
|
||||
/* Set byte to interesting value. */
|
||||
|
||||
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 2: {
|
||||
|
||||
/* Set word to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
|
||||
break;
|
||||
case 1:
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 3: {
|
||||
|
||||
/* Set dword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 4: {
|
||||
|
||||
/* Set qword to interesting value, randomly choosing endian. */
|
||||
|
||||
if (end - begin < 8) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 7) break;
|
||||
|
||||
switch (RAND_BELOW(2)) {
|
||||
|
||||
case 0:
|
||||
*(u64 *)(out_buf + byte_idx) =
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
||||
break;
|
||||
case 1:
|
||||
*(u64 *)(out_buf + byte_idx) = SWAP64(
|
||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 5: {
|
||||
|
||||
/* Randomly subtract from byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 6: {
|
||||
|
||||
/* Randomly add to byte. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 7: {
|
||||
|
||||
/* Randomly subtract from word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 8: {
|
||||
|
||||
/* Randomly add to word, random endian. */
|
||||
|
||||
if (end - begin < 2) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 1) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u16 *)(out_buf + byte_idx) =
|
||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 9: {
|
||||
|
||||
/* Randomly subtract from dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 10: {
|
||||
|
||||
/* Randomly add to dword, random endian. */
|
||||
|
||||
if (end - begin < 4) break;
|
||||
|
||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
||||
|
||||
if (byte_idx >= end - 3) break;
|
||||
|
||||
if (RAND_BELOW(2)) {
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
} else {
|
||||
|
||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
||||
|
||||
*(u32 *)(out_buf + byte_idx) =
|
||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 11: {
|
||||
|
||||
/* Just set a random byte to a random value. Because,
|
||||
why not. We use XOR with 1-255 to eliminate the
|
||||
possibility of a no-op. */
|
||||
|
||||
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This function calculates the next power of 2 greater or equal its argument.
|
||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
||||
*/
|
||||
static inline size_t next_pow2(size_t in) {
|
||||
|
||||
if (in == 0 || in > (size_t)-1)
|
||||
return 0; /* avoid undefined behaviour under-/overflow */
|
||||
size_t out = in - 1;
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
return out + 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(size_needed && *size >= size_needed)) return *buf;
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = realloc(*buf, next_size);
|
||||
*size = *buf ? next_size : 0;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
||||
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
|
||||
size_t *size2) {
|
||||
|
||||
void * scratch_buf = *buf1;
|
||||
size_t scratch_size = *size1;
|
||||
*buf1 = *buf2;
|
||||
*size1 = *size2;
|
||||
*buf2 = scratch_buf;
|
||||
*size2 = scratch_size;
|
||||
|
||||
}
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif
|
||||
|
376
examples/custom_mutators/example.c
Normal file
376
examples/custom_mutators/example.c
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
New Custom Mutator for AFL++
|
||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Shengtuo Hu <h1994st@gmail.com>
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
*/
|
||||
|
||||
// You need to use -I /path/to/AFLplusplus/include
|
||||
#include "custom_mutator_helpers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DATA_SIZE (100)
|
||||
|
||||
static const char *commands[] = {
|
||||
|
||||
"GET",
|
||||
"PUT",
|
||||
"DEL",
|
||||
|
||||
};
|
||||
|
||||
typedef struct my_mutator {
|
||||
|
||||
afl_t *afl;
|
||||
|
||||
// any additional data here!
|
||||
size_t trim_size_current;
|
||||
int trimmming_steps;
|
||||
int cur_step;
|
||||
|
||||
// Reused buffers:
|
||||
BUF_VAR(u8, fuzz);
|
||||
BUF_VAR(u8, data);
|
||||
BUF_VAR(u8, havoc);
|
||||
BUF_VAR(u8, trim);
|
||||
BUF_VAR(u8, post_process);
|
||||
|
||||
} my_mutator_t;
|
||||
|
||||
/**
|
||||
* Initialize this custom mutator
|
||||
*
|
||||
* @param[in] afl a pointer to the internal state object. Can be ignored for
|
||||
* now.
|
||||
* @param[in] seed A seed for this mutator - the same seed should always mutate
|
||||
* in the same way.
|
||||
* @return Pointer to the data object this custom mutator instance should use.
|
||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||
* Return NULL on error.
|
||||
*/
|
||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
||||
|
||||
srand(seed); // needed also by surgical_havoc_mutate()
|
||||
|
||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||
if (!data) {
|
||||
|
||||
perror("afl_custom_init alloc");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
data->afl = afl;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
* (Optional for now. Required in the future)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to input data to be mutated
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
|
||||
* error.
|
||||
* @param[in] add_buf Buffer containing the additional test case
|
||||
* @param[in] add_buf_size Size of the additional test case
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must not
|
||||
* produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
u8 **out_buf, uint8_t *add_buf,
|
||||
size_t add_buf_size, // add_buf can be NULL
|
||||
size_t max_size) {
|
||||
|
||||
// Make sure that the packet size does not exceed the maximum size expected by
|
||||
// the fuzzer
|
||||
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
|
||||
|
||||
// maybe_grow is optimized to be quick for reused buffers.
|
||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
|
||||
if (!mutated_out) {
|
||||
|
||||
*out_buf = NULL;
|
||||
perror("custom mutator allocation (maybe_grow)");
|
||||
return 0; /* afl-fuzz will very likely error out after this. */
|
||||
|
||||
}
|
||||
|
||||
// Randomly select a command string to add as a header to the packet
|
||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||
|
||||
// Mutate the payload of the packet
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
|
||||
// Randomly perform one of the (no len modification) havoc mutations
|
||||
surgical_havoc_mutate(mutated_out, 3, mutated_size);
|
||||
|
||||
}
|
||||
|
||||
*out_buf = mutated_out;
|
||||
return mutated_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A post-processing function to use right before AFL writes the test case to
|
||||
* disk in order to execute the target.
|
||||
*
|
||||
* (Optional) If this functionality is not needed, simply don't define this
|
||||
* function.
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Buffer containing the test case to be executed
|
||||
* @param[in] buf_size Size of the test case
|
||||
* @param[out] out_buf Pointer to the buffer containing the test case after
|
||||
* processing. External library should allocate memory for out_buf.
|
||||
* The buf pointer may be reused (up to the given buf_size);
|
||||
* @return Size of the output buffer after processing or the needed amount.
|
||||
* A return of 0 indicates an error.
|
||||
*/
|
||||
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size, uint8_t **out_buf) {
|
||||
|
||||
uint8_t *post_process_buf =
|
||||
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
|
||||
if (!post_process_buf) {
|
||||
|
||||
perror("custom mutator realloc failed.");
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
memcpy(post_process_buf + 5, buf, buf_size);
|
||||
post_process_buf[0] = 'A';
|
||||
post_process_buf[1] = 'F';
|
||||
post_process_buf[2] = 'L';
|
||||
post_process_buf[3] = '+';
|
||||
post_process_buf[4] = '+';
|
||||
|
||||
*out_buf = post_process_buf;
|
||||
|
||||
return buf_size + 5;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called at the start of each trimming operation and receives
|
||||
* the initial buffer. It should return the amount of iteration steps possible
|
||||
* on this input (e.g. if your input has n elements and you want to remove
|
||||
* them one by one, return n, if you do a binary search, return log(n),
|
||||
* and so on...).
|
||||
*
|
||||
* If your trimming algorithm doesn't allow you to determine the amount of
|
||||
* (remaining) steps easily (esp. while running), then you can alternatively
|
||||
* return 1 here and always return 0 in post_trim until you are finished and
|
||||
* no steps remain. In that case, returning 1 in post_trim will end the
|
||||
* trimming routine. The whole current index/max iterations stuff is only used
|
||||
* to show progress.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param buf Buffer containing the test case
|
||||
* @param buf_size Size of the test case
|
||||
* @return The amount of possible iteration steps to trim the input.
|
||||
* negative on error.
|
||||
*/
|
||||
int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
|
||||
size_t buf_size) {
|
||||
|
||||
// We simply trim once
|
||||
data->trimmming_steps = 1;
|
||||
|
||||
data->cur_step = 0;
|
||||
|
||||
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
|
||||
|
||||
perror("init_trim grow");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
memcpy(data->trim_buf, buf, buf_size);
|
||||
|
||||
data->trim_size_current = buf_size;
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called for each trimming operation. It doesn't have any
|
||||
* arguments because we already have the initial buffer from init_trim and we
|
||||
* can memorize the current state in *data. This can also save
|
||||
* reparsing steps for each iteration. It should return the trimmed input
|
||||
* buffer, where the returned data must not exceed the initial input data in
|
||||
* length. Returning anything that is larger than the original data (passed
|
||||
* to init_trim) will result in a fatal abort of AFLFuzz.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[out] out_buf Pointer to the buffer containing the trimmed test case.
|
||||
* External library should allocate memory for out_buf.
|
||||
* AFL++ will not release the memory after saving the test case.
|
||||
* Keep a ref in *data.
|
||||
* *out_buf = NULL is treated as error.
|
||||
* @return Pointer to the size of the trimmed test case
|
||||
*/
|
||||
size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) {
|
||||
|
||||
*out_buf = data->trim_buf;
|
||||
|
||||
// Remove the last byte of the trimming input
|
||||
return data->trim_size_current - 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after each trim operation to inform you if your
|
||||
* trimming step was successful or not (in terms of coverage). If you receive
|
||||
* a failure here, you should reset your input to the last known good state.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param success Indicates if the last trim operation was successful.
|
||||
* @return The next trim iteration index (from 0 to the maximum amount of
|
||||
* steps returned in init_trim). negative ret on failure.
|
||||
*/
|
||||
int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
|
||||
|
||||
if (success) {
|
||||
|
||||
++data->cur_step;
|
||||
return data->cur_step;
|
||||
|
||||
}
|
||||
|
||||
return data->trimmming_steps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a single custom mutation on a given input.
|
||||
* This mutation is stacked with the other muatations in havoc.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param[in] buf Pointer to the input data to be mutated and the mutated
|
||||
* output
|
||||
* @param[in] buf_size Size of input data
|
||||
* @param[out] out_buf The output buffer. buf can be reused, if the content
|
||||
* fits. *out_buf = NULL is treated as error.
|
||||
* @param[in] max_size Maximum size of the mutated output. The mutation must
|
||||
* not produce data larger than max_size.
|
||||
* @return Size of the mutated output.
|
||||
*/
|
||||
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
|
||||
u8 **out_buf, size_t max_size) {
|
||||
|
||||
if (buf_size == 0) {
|
||||
|
||||
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
|
||||
if (!*out_buf) {
|
||||
|
||||
perror("custom havoc: maybe_grow");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
**out_buf = rand() % 256;
|
||||
buf_size = 1;
|
||||
|
||||
} else {
|
||||
|
||||
// We reuse buf here. It's legal and faster.
|
||||
*out_buf = buf;
|
||||
|
||||
}
|
||||
|
||||
size_t victim = rand() % buf_size;
|
||||
(*out_buf)[victim] += rand() % 10;
|
||||
|
||||
return buf_size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability (in percentage) that afl_custom_havoc_mutation
|
||||
* is called in havoc. By default it is 6 %.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @return The probability (0-100).
|
||||
*/
|
||||
uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
|
||||
|
||||
return 5; // 5 %
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the fuzzer should fuzz the queue entry or not.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param[in] data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename File name of the test case in the queue entry
|
||||
* @return Return True(1) if the fuzzer will fuzz the queue entry, and
|
||||
* False(0) otherwise.
|
||||
*/
|
||||
uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for additional analysis (e.g. calling a different tool that does a
|
||||
* different kind of coverage and saves this for the custom mutator).
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||
* @param filename_new_queue File name of the new queue entry
|
||||
* @param filename_orig_queue File name of the original queue entry
|
||||
*/
|
||||
void afl_custom_queue_new_entry(my_mutator_t * data,
|
||||
const uint8_t *filename_new_queue,
|
||||
const uint8_t *filename_orig_queue) {
|
||||
|
||||
/* Additional analysis on the original or new test case */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(my_mutator_t *data) {
|
||||
|
||||
free(data->post_process_buf);
|
||||
free(data->havoc_buf);
|
||||
free(data->data_buf);
|
||||
free(data->fuzz_buf);
|
||||
free(data->trim_buf);
|
||||
free(data);
|
||||
|
||||
}
|
||||
|
@ -16,31 +16,49 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
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
|
||||
|
||||
@ -50,54 +68,119 @@ def fuzz(buf, add_buf):
|
||||
# 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
|
@ -16,27 +16,32 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def init(seed):
|
||||
'''
|
||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||
|
||||
|
||||
@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
|
||||
'''
|
||||
@ -45,10 +50,10 @@ def fuzz(buf, add_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))
|
||||
|
74
examples/custom_mutators/simple_example.c
Normal file
74
examples/custom_mutators/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 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);
|
||||
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
Simple Custom Mutator for AFL
|
||||
|
||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||
|
||||
This a simple mutator that assumes that the generates messages starting with
|
||||
one of the three strings GET, PUT, or DEL followed by a payload. The mutator
|
||||
randomly selects a commend and mutates the payload of the seed provided as
|
||||
input.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *commands[] = {
|
||||
|
||||
"GET",
|
||||
"PUT",
|
||||
"DEL",
|
||||
|
||||
};
|
||||
|
||||
static size_t data_size = 100;
|
||||
|
||||
size_t afl_custom_mutator(uint8_t *data, size_t size, uint8_t *mutated_out,
|
||||
size_t max_size, unsigned int seed) {
|
||||
|
||||
// Seed the PRNG
|
||||
srand(seed);
|
||||
|
||||
// Make sure that the packet size does not exceed the maximum size expected by
|
||||
// the fuzzer
|
||||
size_t mutated_size = data_size <= max_size ? data_size : max_size;
|
||||
|
||||
// Randomly select a command string to add as a header to the packet
|
||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||
|
||||
// Mutate the payload of the packet
|
||||
for (int i = 3; i < mutated_size; i++) {
|
||||
|
||||
mutated_out[i] = (data[i] + rand() % 10) & 0xff;
|
||||
|
||||
}
|
||||
|
||||
return mutated_size;
|
||||
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ __seed__ = "RANDOM"
|
||||
__log__ = False
|
||||
__log_file__ = "wrapper.log"
|
||||
|
||||
# AFL functions
|
||||
|
||||
# AFL functions
|
||||
def log(text):
|
||||
"""
|
||||
Logger
|
||||
Logger
|
||||
"""
|
||||
|
||||
global __seed__
|
||||
@ -24,6 +24,7 @@ def log(text):
|
||||
with open(__log_file__, "a") as logf:
|
||||
logf.write("[%s] %s\n" % (__seed__, text))
|
||||
|
||||
|
||||
def init(seed):
|
||||
"""
|
||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||
@ -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")
|
||||
|
||||
@ -71,28 +73,28 @@ def fuzz(buf, add_buf):
|
||||
try:
|
||||
__mutator__.init_from_string(buf_str)
|
||||
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
||||
except:
|
||||
except Exception:
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||
|
||||
# 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,8 +102,8 @@ def fuzz(buf, add_buf):
|
||||
log("fuzz(): Returning %d bytes" % len(data))
|
||||
return data
|
||||
|
||||
# Main (for debug)
|
||||
|
||||
# Main (for debug)
|
||||
if __name__ == '__main__':
|
||||
|
||||
__log__ = True
|
||||
@ -114,4 +116,3 @@ if __name__ == '__main__':
|
||||
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
||||
out = fuzz(in_1, in_2)
|
||||
print(out)
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
/* Main entry point. */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
ssize_t len; /* how much input did we read? */
|
||||
char buf[100]; /* Example-only buffer, you'd replace it with other global or
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - postprocessor library example
|
||||
--------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Copyright 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
|
||||
|
||||
Postprocessor libraries can be passed to afl-fuzz to perform final cleanup
|
||||
of any mutated test cases - for example, to fix up checksums in PNG files.
|
||||
|
||||
Please heed the following warnings:
|
||||
|
||||
1) In almost all cases, it is more productive to comment out checksum logic
|
||||
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.
|
||||
|
||||
3) Postprocessors that do anything non-trivial must be extremely robust to
|
||||
gracefully handle malformed data and other error conditions - otherwise,
|
||||
they will crash and take afl-fuzz down with them. Be wary of reading past
|
||||
*len and of integer overflows when calculating file offsets.
|
||||
|
||||
In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really,
|
||||
honestly know what you're doing =)
|
||||
|
||||
With that out of the way: the postprocessor library is passed to afl-fuzz
|
||||
via AFL_POST_LIBRARY. The library must be compiled with:
|
||||
|
||||
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:
|
||||
|
||||
1) If you don't want to modify the test case, simply return the original
|
||||
buffer pointer ('in_buf').
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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. ***
|
||||
|
||||
Aight. 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
|
||||
Ben Nagy instead: https://github.com/bnagy/aflfix
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Header that must be present at the beginning of every test case: */
|
||||
|
||||
#define HEADER "GIF89a"
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Skip execution altogether for buffers shorter than 6 bytes (just to
|
||||
show how it's done). We can trust *len to be sane. */
|
||||
|
||||
if (*len < strlen(HEADER)) return NULL;
|
||||
|
||||
/* Do nothing for buffers that already start with the expected header. */
|
||||
|
||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf;
|
||||
|
||||
/* Allocate memory for new buffer, reusing previous allocation if
|
||||
possible. */
|
||||
|
||||
new_buf = realloc(saved_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;
|
||||
|
||||
/* Copy the original data to the new location. */
|
||||
|
||||
memcpy(new_buf, in_buf, *len);
|
||||
|
||||
/* Insert the new header. */
|
||||
|
||||
memcpy(new_buf, HEADER, strlen(HEADER));
|
||||
|
||||
/* Return modified buffer. No need to update *len in this particular case,
|
||||
as we're not changing it. */
|
||||
|
||||
return new_buf;
|
||||
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - postprocessor for PNG
|
||||
------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Copyright 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
|
||||
|
||||
See post_library.so.c for a general discussion of how to implement
|
||||
postprocessors. This specific postprocessor attempts to fix up PNG
|
||||
checksums, providing a slightly more complicated example than found
|
||||
in post_library.so.c.
|
||||
|
||||
Compile with:
|
||||
|
||||
gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* A macro to round an integer up to 4 kB. */
|
||||
|
||||
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
|
||||
|
||||
const unsigned char* afl_postprocess(const unsigned char* in_buf,
|
||||
unsigned int* len) {
|
||||
|
||||
static unsigned char* saved_buf;
|
||||
static unsigned int saved_len;
|
||||
|
||||
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;
|
||||
|
||||
/* 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) {
|
||||
|
||||
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));
|
||||
|
||||
/* Bail out if chunk size is too big or goes past EOF. */
|
||||
|
||||
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > *len) break;
|
||||
|
||||
/* Chunk checksum is calculated for chunk ID (dword) and the actual
|
||||
payload. */
|
||||
|
||||
real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4));
|
||||
|
||||
/* The in-file checksum is the last dword past the chunk data. */
|
||||
|
||||
file_cksum = *(uint32_t*)(in_buf + pos + 8 + chunk_len);
|
||||
|
||||
/* If the checksums do not match, we need to fix the file. */
|
||||
|
||||
if (real_cksum != file_cksum) {
|
||||
|
||||
/* First modification? Make a copy of the input buffer. Round size
|
||||
up to 4 kB to minimize the number of reallocs needed. */
|
||||
|
||||
if (new_buf == in_buf) {
|
||||
|
||||
if (*len <= saved_len) {
|
||||
|
||||
new_buf = saved_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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*(uint32_t*)(new_buf + pos + 8 + chunk_len) = real_cksum;
|
||||
|
||||
}
|
||||
|
||||
/* Skip the entire chunk and move to the next one. */
|
||||
|
||||
pos += 12 + chunk_len;
|
||||
|
||||
}
|
||||
|
||||
return new_buf;
|
||||
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
These are example and helper files for the AFL_PYTHON_MODULE feature.
|
||||
See [docs/python_mutators.md](../docs/python_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use pyton2.7 to compile python2 scripts!
|
||||
|
||||
|
||||
example.py - this is the template you can use, the functions are there
|
||||
but they are empty
|
||||
|
||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||
|
||||
common.py - this can be used for common functions and helpers.
|
||||
the examples do not use this though. But you can :)
|
||||
|
||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||
|
||||
XmlMutatorMin.py - module for XML mutation
|
@ -2,7 +2,7 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define g2h(x) ((void*)((unsigned long)(x) + guest_base))
|
||||
#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
|
||||
#define h2g(x) ((uint64_t)(x)-guest_base)
|
||||
|
||||
enum {
|
||||
@ -35,15 +35,16 @@ enum {
|
||||
|
||||
};
|
||||
|
||||
void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) {
|
||||
void afl_persistent_hook(uint64_t *regs, uint64_t guest_base) {
|
||||
|
||||
// In this example the register RDI is pointing to the memory location
|
||||
// of the target buffer, and the length of the input is in RAX.
|
||||
// of the target buffer, and the length of the input is in RSI.
|
||||
// This can be seen with a debugger, e.g. gdb (and "disass main")
|
||||
|
||||
printf("reading into %p\n", regs[R_EDI]);
|
||||
size_t r = read(0, g2h(regs[R_EDI]), 1024);
|
||||
regs[R_EAX] = r;
|
||||
printf("readed %ld bytes\n", r);
|
||||
regs[R_ESI] = r;
|
||||
printf("read %ld bytes\n", r);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int target_func(char *buf, int size) {
|
||||
int target_func(unsigned char *buf, int size) {
|
||||
|
||||
printf("buffer:%p, size:%p\n", buf, size);
|
||||
switch (buf[0]) {
|
||||
@ -16,7 +16,8 @@ int target_func(char *buf, int size) {
|
||||
}
|
||||
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,26 +18,39 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
CFLAGS = -fPIC -Wall -Wextra
|
||||
LDFLAGS = -shared
|
||||
|
||||
ifneq "$(filter Linux GNU%,$(shell uname))" ""
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
|
||||
UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
|
||||
|
||||
_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
# on gcc for arm there is no -m32, but -mbe32
|
||||
M32FLAG = -m32
|
||||
M64FLAG = -m64
|
||||
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
M32FLAG = -mbe32
|
||||
endif
|
||||
endif
|
||||
|
||||
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
|
||||
CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
|
||||
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
|
||||
CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
|
||||
|
||||
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
|
||||
__M32FLAG=$(_M32FLAG:00=-mbe32)
|
||||
___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
|
||||
M32FLAG=$(___M32FLAG)
|
||||
#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
|
||||
# M32FLAG = -mbe32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
all: socketfuzz32.so socketfuzz64.so
|
||||
|
||||
socketfuzz32.so: socketfuzz.c
|
||||
-$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "socketfuzz32 build failure (that's fine)"
|
||||
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)"
|
||||
|
||||
socketfuzz64.so: socketfuzz.c
|
||||
-$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "socketfuzz64 build failure (that's fine)"
|
||||
-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)"
|
||||
|
||||
install: socketfuzz32.so socketfuzz64.so
|
||||
install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
|
||||
|
160
gcc_plugin/GNUmakefile
Normal file
160
gcc_plugin/GNUmakefile
Normal file
@ -0,0 +1,160 @@
|
||||
#
|
||||
# american fuzzy lop++ - GCC plugin instrumentation
|
||||
# -----------------------------------------------
|
||||
#
|
||||
# Written by Austin Seipp <aseipp@pobox.com> and
|
||||
# Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski and
|
||||
# Heiko Eißfeldt <heiko@hexco.de>
|
||||
#
|
||||
# GCC integration design is based on the LLVM design, which comes
|
||||
# from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS = -Wall -I../include -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS := $(CXXFLAGS) -Wall
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
ifeq "clang" "$(CC)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
ifeq "clang++" "$(CXX)"
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
endif
|
||||
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include"
|
||||
HASH=\#
|
||||
|
||||
GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCBINDIR = $(shell dirname `command -v $(CC)` 2>/dev/null )
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
|
||||
|
||||
|
||||
all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps
|
||||
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-gcc-fast ../afl-g++-fast
|
||||
|
||||
../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-gcc-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-gcc-fast.8 ../afl-g++-fast.8
|
||||
|
||||
install: all
|
||||
install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH)
|
||||
install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
install -m 644 -T README.whitelist.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.whitelist.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
@ -21,87 +21,104 @@
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops
|
||||
CFLAGS += -Wall -I../include -D_FORTIFY_SOURCE=2 -Wno-pointer-sign \
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
VERSION:sh= grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2
|
||||
|
||||
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS = -Wall -I../include -Wno-pointer-sign \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
|
||||
-Wno-unused-function
|
||||
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops
|
||||
CXXEFLAGS := $(CXXFLAGS) -Wall -D_FORTIFY_SOURCE=2
|
||||
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CXXEFLAGS = $(CXXFLAGS) -Wall
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include"
|
||||
MYCC=$(CC:clang=gcc)
|
||||
MYCXX=$(CXX:clang++=g++)
|
||||
|
||||
PLUGIN_PATH = $(shell $(MYCC) -print-file-name=plugin)
|
||||
PLUGIN_PATH:sh= $(MYCC) -print-file-name=plugin
|
||||
PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(PLUGIN_PATH)/include"
|
||||
HASH=\#
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
GCCVER = $(shell $(MYCC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
|
||||
GCCBINDIR = $(shell dirname `command -v $(MYCC)` 2>/dev/null )
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
_SHMAT_OK= $(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )
|
||||
_SHMAT_OK:sh= echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(MYCC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2
|
||||
|
||||
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
|
||||
IGNORE_MMAP=$(TEST_MMAP:1=0)
|
||||
__SHMAT_OK=$(_SHMAT_OK)$(IGNORE_MMAP)
|
||||
___SHMAT_OK=$(__SHMAT_OK:10=0)
|
||||
SHMAT_OK=$(___SHMAT_OK:1=1)
|
||||
_CFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
CFLAGS_ADD=$(_CFLAGS_ADD:0=-DUSEMMAP=1)
|
||||
|
||||
_LDFLAGS_ADD=$(SHMAT_OK:1=)
|
||||
LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt)
|
||||
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
LDFLAGS += $(LDFLAGS_ADD)
|
||||
|
||||
PROGS = ../afl-gcc-pass.so ../afl-gcc-fast ../afl-gcc-rt.o
|
||||
|
||||
all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
debug:
|
||||
@echo _SHMAT_OK = $(_SHMAT_OK)
|
||||
@echo IGNORE_MMAP = $(IGNORE_MMAP)
|
||||
@echo __SHMAT_OK = $(__SHMAT_OK)
|
||||
@echo ___SHMAT_OK = $(___SHMAT_OK)
|
||||
@echo SHMAT_OK = $(SHMAT_OK)
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
@if [ "$(SHMAT_OK)" == "1" ]; then \
|
||||
echo "[+] shmat seems to be working."; \
|
||||
rm -f .test2; \
|
||||
else \
|
||||
echo "[-] shmat seems not to be working, switching to mmap implementation"; \
|
||||
fi
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for working '$(MYCC)'..."
|
||||
@type $(MYCC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(MYCC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
# @echo "[*] Checking for gcc for plugin support..."
|
||||
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
# @$(MYCC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
|
||||
@echo "[*] Checking for gcc plugin development header files..."
|
||||
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@test -d `$(MYCC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
$(MYCC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-gcc-fast: afl-gcc-fast.c afl-common.o | test_deps
|
||||
$(CC) -DAFL_GCC_CC=\"$(CC)\" -DAFL_GCC_CXX=\"$(CXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
$(MYCC) -DAFL_GCC_CC=\"$(MYCC)\" -DAFL_GCC_CXX=\"$(MYCXX)\" $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-gcc-fast ../afl-g++-fast
|
||||
|
||||
../afl-gcc-pass.so: afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
$(MYCXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
|
||||
../afl-gcc-rt.o: afl-gcc-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
$(MYCC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN; AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
# unset AFL_USE_ASAN AFL_USE_MSAN; AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ../afl-gcc-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr </dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@ -109,7 +126,7 @@ all_done: test_build
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
VPATH = ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@ -123,13 +140,19 @@ vpath % ..
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-gcc-fast.8 ../afl-g++-fast.8
|
||||
|
||||
install: all
|
||||
install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH)
|
||||
install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
|
||||
install -m 644 -T README.whitelist.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.whitelist.md
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
|
||||
rm -f $(PROGS) afl-common.o ../afl-g++-fast ../afl-g*-fast.8
|
||||
|
@ -37,16 +37,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static u8* obj_path; /* Path to runtime libraries */
|
||||
static u8** cc_params; /* Parameters passed to the real CC */
|
||||
static u8 * obj_path; /* Path to runtime libraries */
|
||||
static u8 **cc_params; /* Parameters passed to the real CC */
|
||||
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
|
||||
u8 use_stdin = 0; /* dummy */
|
||||
|
||||
/* Try to find the runtime libraries. If that fails, abort. */
|
||||
|
||||
static void find_obj(u8* argv0) {
|
||||
static void find_obj(u8 *argv0) {
|
||||
|
||||
u8* afl_path = getenv("AFL_PATH");
|
||||
u8 *afl_path = getenv("AFL_PATH");
|
||||
u8 *slash, *tmp;
|
||||
|
||||
if (afl_path) {
|
||||
@ -69,7 +69,7 @@ static void find_obj(u8* argv0) {
|
||||
|
||||
if (slash) {
|
||||
|
||||
u8* dir;
|
||||
u8 *dir;
|
||||
|
||||
*slash = 0;
|
||||
dir = ck_strdup(argv0);
|
||||
@ -105,12 +105,12 @@ static void find_obj(u8* argv0) {
|
||||
|
||||
/* Copy argv to cc_params, making the necessary edits. */
|
||||
|
||||
static void edit_params(u32 argc, char** argv) {
|
||||
static void edit_params(u32 argc, char **argv) {
|
||||
|
||||
u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1;
|
||||
u8* name;
|
||||
u8 *name;
|
||||
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
|
||||
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
|
||||
|
||||
name = strrchr(argv[0], '/');
|
||||
if (!name)
|
||||
@ -120,17 +120,23 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
if (!strcmp(name, "afl-g++-fast")) {
|
||||
|
||||
u8* alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx ? alt_cxx : (u8*)AFL_GCC_CXX;
|
||||
u8 *alt_cxx = getenv("AFL_CXX");
|
||||
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
|
||||
|
||||
} else if (!strcmp(name, "afl-gcc-fast")) {
|
||||
|
||||
u8 *alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
|
||||
|
||||
} else {
|
||||
|
||||
u8* alt_cc = getenv("AFL_CC");
|
||||
cc_params[0] = alt_cc ? alt_cc : (u8*)AFL_GCC_CC;
|
||||
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
|
||||
FATAL(
|
||||
"Name of the binary is not a known name, expected afl-(gcc|g++)-fast");
|
||||
|
||||
}
|
||||
|
||||
char* fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
|
||||
char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
|
||||
cc_params[cc_par_cnt++] = fplugin_arg;
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
@ -139,7 +145,7 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
while (--argc) {
|
||||
|
||||
u8* cur = *(++argv);
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
if (!strcmp(cur, "-m32")) FATAL("-m32 is not supported");
|
||||
@ -296,7 +302,7 @@ static void edit_params(u32 argc, char** argv) {
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
|
||||
|
||||
@ -323,10 +329,24 @@ int main(int argc, char** argv, char** envp) {
|
||||
"programs\n"
|
||||
"(similarly to the LLVM plugin used by afl-clang-fast).\n\n"
|
||||
|
||||
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
|
||||
"Setting\n"
|
||||
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
|
||||
BIN_PATH, BIN_PATH);
|
||||
"Environment variables used:\n"
|
||||
"AFL_CC: path to the C compiler to use\n"
|
||||
"AFL_CXX: path to the C++ compiler to use\n"
|
||||
"AFL_PATH: path to instrumenting pass and runtime (afl-gcc-rt.*o)\n"
|
||||
"AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
|
||||
"AFL_INST_RATIO: percentage of branches to instrument\n"
|
||||
"AFL_QUIET: suppress verbose output\n"
|
||||
"AFL_DEBUG: enable developer debugging output\n"
|
||||
"AFL_HARDEN: adds code hardening to catch memory bugs\n"
|
||||
"AFL_USE_ASAN: activate address sanitizer\n"
|
||||
"AFL_USE_MSAN: activate memory sanitizer\n"
|
||||
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
|
||||
"AFL_GCC_WHITELIST: enable whitelisting (selective instrumentation)\n"
|
||||
|
||||
"\nafl-gcc-fast was built for gcc %s with the gcc binary path of "
|
||||
"\"%s\".\n\n",
|
||||
BIN_PATH, BIN_PATH, GCC_VERSION, GCC_BINDIR);
|
||||
|
||||
exit(1);
|
||||
|
||||
@ -346,6 +366,18 @@ int main(int argc, char** argv, char** envp) {
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
u8 *ptr;
|
||||
if (!be_quiet &&
|
||||
((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
|
||||
|
||||
u32 map_size = atoi(ptr);
|
||||
if (map_size != MAP_SIZE)
|
||||
FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast");
|
||||
|
||||
}
|
||||
|
||||
check_environment_vars(envp);
|
||||
@ -361,7 +393,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
}
|
||||
|
||||
*/
|
||||
execvp(cc_params[0], (char**)cc_params);
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
|
||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||
|
||||
|
@ -52,13 +52,13 @@
|
||||
#include "../config.h"
|
||||
#include "../include/debug.h"
|
||||
|
||||
/* clear helper AFL types pulls in, which intervene with gcc-plugin geaders from
|
||||
* GCC-8 */
|
||||
/* clear helper macros AFL types pull in, which intervene with gcc-plugin
|
||||
* headers from GCC-8 */
|
||||
#ifdef likely
|
||||
#undef likely
|
||||
#undef likely
|
||||
#endif
|
||||
#ifdef unlikely
|
||||
#undef unlikely
|
||||
#undef unlikely
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@ -295,16 +295,16 @@ static unsigned int inline_instrument(function *fun) {
|
||||
update_stmt(g);
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
#if 0
|
||||
tree addr = build2(ADDR_EXPR, map_type, map_ptr, area_off);
|
||||
g = gimple_build_assign(map_ptr2, MODIFY_EXPR, addr);
|
||||
gimple_seq_add_stmt(&seq, g); // map_ptr2 = map_ptr + area_off
|
||||
update_stmt(g);
|
||||
#else
|
||||
#else
|
||||
g = gimple_build_assign(map_ptr2, PLUS_EXPR, map_ptr, area_off);
|
||||
gimple_seq_add_stmt(&seq, g); // map_ptr2 = map_ptr + area_off
|
||||
update_stmt(g);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// gimple_assign <mem_ref, _3, *p_6, NULL, NULL>
|
||||
tree tmp1 = create_tmp_var_raw(unsigned_char_type_node, "tmp1");
|
||||
@ -567,7 +567,7 @@ int plugin_init(struct plugin_name_args * plugin_info,
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instWhiteListFilename);
|
||||
if (!fileStream) fatal_error(0, "Unable to open AFL_GCC_WHITELIST");
|
||||
if (!fileStream) PFATAL("Unable to open AFL_GCC_WHITELIST");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
|
@ -20,11 +20,14 @@
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android-ashmem.h"
|
||||
#include "android-ashmem.h"
|
||||
#endif
|
||||
#include "../config.h"
|
||||
#include "../types.h"
|
||||
|
||||
#ifdef USEMMAP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
@ -48,8 +51,10 @@ u8 *__afl_area_ptr = __afl_area_initial;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
u32 __afl_prev_loc;
|
||||
u32 __afl_final_loc;
|
||||
#else
|
||||
__thread u32 __afl_prev_loc;
|
||||
__thread u32 __afl_final_loc;
|
||||
#endif
|
||||
|
||||
/* Trace a basic block with some ID */
|
||||
@ -92,7 +97,7 @@ static void __afl_map_shm(void) {
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
printf("shm_open() failed\n");
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -104,7 +109,7 @@ static void __afl_map_shm(void) {
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
printf("mmap() failed\n");
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
exit(2);
|
||||
|
||||
}
|
||||
@ -133,8 +138,9 @@ static void __afl_map_shm(void) {
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
static u8 tmp[4];
|
||||
s32 child_pid;
|
||||
u8 tmp[4] = {0, 0, 0, 0};
|
||||
u32 map_size = MAP_SIZE;
|
||||
s32 child_pid;
|
||||
|
||||
u8 child_stopped = 0;
|
||||
|
||||
@ -143,6 +149,13 @@ static void __afl_start_forkserver(void) {
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (MAP_SIZE <= 0x800000) {
|
||||
|
||||
map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
|
||||
memcpy(tmp, &map_size, 4);
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
|
||||
|
||||
while (1) {
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -107,7 +108,7 @@
|
||||
|
||||
*/
|
||||
|
||||
static const u8* trampoline_fmt_32 =
|
||||
static const u8 *trampoline_fmt_32 =
|
||||
|
||||
"\n"
|
||||
"/* --- AFL TRAMPOLINE (32-BIT) --- */\n"
|
||||
@ -130,7 +131,7 @@ static const u8* trampoline_fmt_32 =
|
||||
"/* --- END --- */\n"
|
||||
"\n";
|
||||
|
||||
static const u8* trampoline_fmt_64 =
|
||||
static const u8 *trampoline_fmt_64 =
|
||||
|
||||
"\n"
|
||||
"/* --- AFL TRAMPOLINE (64-BIT) --- */\n"
|
||||
@ -151,7 +152,7 @@ static const u8* trampoline_fmt_64 =
|
||||
"/* --- END --- */\n"
|
||||
"\n";
|
||||
|
||||
static const u8* main_payload_32 =
|
||||
static const u8 *main_payload_32 =
|
||||
|
||||
"\n"
|
||||
"/* --- AFL MAIN PAYLOAD (32-BIT) --- */\n"
|
||||
@ -384,6 +385,7 @@ static const u8* main_payload_32 =
|
||||
#ifndef COVERAGE_ONLY
|
||||
" .comm __afl_prev_loc, 4, 32\n"
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
" .comm __afl_final_loc, 4, 32\n"
|
||||
" .comm __afl_fork_pid, 4, 32\n"
|
||||
" .comm __afl_temp, 4, 32\n"
|
||||
"\n"
|
||||
@ -402,12 +404,12 @@ static const u8* main_payload_32 =
|
||||
recognize .string. */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define CALL_L64(str) "call _" str "\n"
|
||||
#define CALL_L64(str) "call _" str "\n"
|
||||
#else
|
||||
#define CALL_L64(str) "call " str "@PLT\n"
|
||||
#define CALL_L64(str) "call " str "@PLT\n"
|
||||
#endif /* ^__APPLE__ */
|
||||
|
||||
static const u8* main_payload_64 =
|
||||
static const u8 *main_payload_64 =
|
||||
|
||||
"\n"
|
||||
"/* --- AFL MAIN PAYLOAD (64-BIT) --- */\n"
|
||||
@ -742,9 +744,9 @@ static const u8* main_payload_64 =
|
||||
#ifdef __APPLE__
|
||||
|
||||
" .comm __afl_area_ptr, 8\n"
|
||||
#ifndef COVERAGE_ONLY
|
||||
#ifndef COVERAGE_ONLY
|
||||
" .comm __afl_prev_loc, 8\n"
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
" .comm __afl_fork_pid, 4\n"
|
||||
" .comm __afl_temp, 4\n"
|
||||
" .comm __afl_setup_failure, 1\n"
|
||||
@ -752,9 +754,9 @@ static const u8* main_payload_64 =
|
||||
#else
|
||||
|
||||
" .lcomm __afl_area_ptr, 8\n"
|
||||
#ifndef COVERAGE_ONLY
|
||||
#ifndef COVERAGE_ONLY
|
||||
" .lcomm __afl_prev_loc, 8\n"
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
#endif /* !COVERAGE_ONLY */
|
||||
" .lcomm __afl_fork_pid, 4\n"
|
||||
" .lcomm __afl_temp, 4\n"
|
||||
" .lcomm __afl_setup_failure, 1\n"
|
||||
|
1154
include/afl-fuzz.h
1154
include/afl-fuzz.h
File diff suppressed because it is too large
Load Diff
142
include/afl-prealloc.h
Normal file
142
include/afl-prealloc.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
american fuzzy lop++ - prealloc a buffer to reuse small elements often
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
/* If we know we'll reuse small elements often, we'll just preallocate a buffer,
|
||||
* then fall back to malloc */
|
||||
// TODO: Replace free status check with bitmask+CLZ
|
||||
|
||||
#ifndef AFL_PREALLOC_H
|
||||
#define AFL_PREALLOC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "alloc-inl.h"
|
||||
|
||||
typedef enum prealloc_status {
|
||||
|
||||
PRE_STATUS_UNUSED = 0, /* free in buf */
|
||||
PRE_STATUS_USED, /* used in buf */
|
||||
PRE_STATUS_MALLOC /* system malloc */
|
||||
|
||||
} pre_status_t;
|
||||
|
||||
/* Adds the entry used for prealloc bookkeeping to this struct */
|
||||
|
||||
/* prealloc status of this instance */
|
||||
#define PREALLOCABLE pre_status_t pre_status
|
||||
|
||||
/* allocate an element of type *el_ptr, to this variable.
|
||||
Uses (and reuses) the given prealloc_buf before hitting libc's malloc.
|
||||
prealloc_buf must be the pointer to an array with type `type`.
|
||||
`type` must be a struct with uses PREALLOCABLE (a pre_status_t pre_status
|
||||
member). prealloc_size must be the array size. prealloc_counter must be a
|
||||
variable initialized with 0 (of any name).
|
||||
*/
|
||||
|
||||
#define PRE_ALLOC(el_ptr, prealloc_buf, prealloc_size, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
if ((prealloc_counter) >= (prealloc_size)) { \
|
||||
\
|
||||
el_ptr = malloc(sizeof(*el_ptr)); \
|
||||
el_ptr->pre_status = PRE_STATUS_MALLOC; \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
/* Find one of our preallocated elements */ \
|
||||
u32 i; \
|
||||
for (i = 0; i < (prealloc_size); i++) { \
|
||||
\
|
||||
el_ptr = &((prealloc_buf)[i]); \
|
||||
if (el_ptr->pre_status == PRE_STATUS_UNUSED) { \
|
||||
\
|
||||
(prealloc_counter)++; \
|
||||
el_ptr->pre_status = PRE_STATUS_USED; \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
if (!el_ptr) { FATAL("BUG in list.h -> no element found or allocated!"); } \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* Take a chosen (free) element from the prealloc_buf directly */
|
||||
|
||||
#define PRE_ALLOC_FORCE(el_ptr, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
if ((el_ptr)->pre_status != PRE_STATUS_UNUSED) { \
|
||||
\
|
||||
FATAL("PRE_ALLOC_FORCE element already allocated"); \
|
||||
\
|
||||
} \
|
||||
(el_ptr)->pre_status = PRE_STATUS_USED; \
|
||||
(prealloc_counter)++; \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* free an preallocated element */
|
||||
|
||||
#define PRE_FREE(el_ptr, prealloc_counter) \
|
||||
do { \
|
||||
\
|
||||
switch ((el_ptr)->pre_status) { \
|
||||
\
|
||||
case PRE_STATUS_USED: { \
|
||||
\
|
||||
(el_ptr)->pre_status = PRE_STATUS_UNUSED; \
|
||||
(prealloc_counter)--; \
|
||||
if ((prealloc_counter) < 0) { \
|
||||
\
|
||||
FATAL("Inconsistent data in PRE_FREE"); \
|
||||
\
|
||||
} \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
case PRE_STATUS_MALLOC: { \
|
||||
\
|
||||
(el_ptr)->pre_status = PRE_STATUS_UNUSED; \
|
||||
DFL_ck_free((el_ptr)); \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
default: { \
|
||||
\
|
||||
FATAL("Double Free Detected"); \
|
||||
break; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
#endif
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -34,70 +35,75 @@
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Initial size used for ck_maybe_grow */
|
||||
#define INITIAL_GROWTH_SIZE (64)
|
||||
|
||||
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
|
||||
|
||||
#ifndef _WANT_ORIGINAL_AFL_ALLOC
|
||||
// afl++ stuff without memory corruption checks - for speed
|
||||
// afl++ stuff without memory corruption checks - for speed
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
#define alloc_printf(_str...) \
|
||||
({ \
|
||||
\
|
||||
u8* _tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char*)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
#define alloc_printf(_str...) \
|
||||
({ \
|
||||
\
|
||||
u8 *_tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char *)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
|
||||
#define ALLOC_CHECK_SIZE(_s) \
|
||||
do { \
|
||||
\
|
||||
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
#define ALLOC_CHECK_SIZE(_s) \
|
||||
do { \
|
||||
\
|
||||
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) \
|
||||
do { \
|
||||
\
|
||||
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) \
|
||||
do { \
|
||||
\
|
||||
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
|
||||
#define ALLOC_BLK_INC 256
|
||||
#define ALLOC_BLK_INC 256
|
||||
|
||||
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
|
||||
requests. */
|
||||
|
||||
static inline void* DFL_ck_alloc_nozero(u32 size) {
|
||||
static inline void *DFL_ck_alloc_nozero(u32 size) {
|
||||
|
||||
u8* ret;
|
||||
void *ret;
|
||||
|
||||
if (!size) return NULL;
|
||||
if (!size) { return NULL; }
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
return (void*)ret;
|
||||
return (void *)ret;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate a buffer, returning zeroed memory. */
|
||||
|
||||
static inline void* DFL_ck_alloc(u32 size) {
|
||||
static inline void *DFL_ck_alloc(u32 size) {
|
||||
|
||||
void* mem;
|
||||
void *mem;
|
||||
|
||||
if (!size) return NULL;
|
||||
if (!size) { return NULL; }
|
||||
mem = DFL_ck_alloc_nozero(size);
|
||||
|
||||
return memset(mem, 0, size);
|
||||
@ -107,9 +113,9 @@ static inline void* DFL_ck_alloc(u32 size) {
|
||||
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
||||
is set, the old memory will be also clobbered with 0xFF. */
|
||||
|
||||
static inline void DFL_ck_free(void* mem) {
|
||||
static inline void DFL_ck_free(void *mem) {
|
||||
|
||||
if (!mem) return;
|
||||
if (!mem) { return; }
|
||||
|
||||
free(mem);
|
||||
|
||||
@ -119,9 +125,9 @@ static inline void DFL_ck_free(void* mem) {
|
||||
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
|
||||
old memory is clobbered with 0xFF. */
|
||||
|
||||
static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
u8* ret;
|
||||
void *ret;
|
||||
|
||||
if (!size) {
|
||||
|
||||
@ -139,14 +145,14 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
return (void*)ret;
|
||||
return (void *)ret;
|
||||
|
||||
}
|
||||
|
||||
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
|
||||
repeated small reallocs without complicating the user code). */
|
||||
|
||||
static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
|
||||
|
||||
return DFL_ck_realloc(orig, size);
|
||||
|
||||
@ -154,14 +160,14 @@ static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
|
||||
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_strdup(u8* str) {
|
||||
static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
u8* ret;
|
||||
u8 *ret;
|
||||
u32 size;
|
||||
|
||||
if (!str) return NULL;
|
||||
if (!str) { return NULL; }
|
||||
|
||||
size = strlen((char*)str) + 1;
|
||||
size = strlen((char *)str) + 1;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size);
|
||||
@ -174,11 +180,11 @@ static inline u8* DFL_ck_strdup(u8* str) {
|
||||
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
||||
or NULL inputs. */
|
||||
|
||||
static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
||||
static inline void *DFL_ck_memdup(void *mem, u32 size) {
|
||||
|
||||
u8* ret;
|
||||
void *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
if (!mem || !size) { return NULL; }
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size);
|
||||
@ -191,11 +197,11 @@ static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
||||
/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
||||
Returns NULL for zero-sized or NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
|
||||
u8* ret;
|
||||
u8 *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
if (!mem || !size) { return NULL; }
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + 1);
|
||||
@ -208,112 +214,111 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
|
||||
}
|
||||
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above functions
|
||||
to user-visible names such as ck_alloc(). */
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above
|
||||
functions to user-visible names such as ck_alloc(). */
|
||||
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
#define alloc_report()
|
||||
|
||||
#else
|
||||
// This is the original alloc-inl of stock afl
|
||||
// This is the original alloc-inl of stock afl
|
||||
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
||||
|
||||
#define alloc_printf(_str...) \
|
||||
({ \
|
||||
\
|
||||
u8* _tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char*)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
#define alloc_printf(_str...) \
|
||||
({ \
|
||||
\
|
||||
u8 *_tmp; \
|
||||
s32 _len = snprintf(NULL, 0, _str); \
|
||||
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
||||
_tmp = ck_alloc(_len + 1); \
|
||||
snprintf((char *)_tmp, _len + 1, _str); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
/* Macro to enforce allocation limits as a last-resort defense against
|
||||
integer overflows. */
|
||||
#define ALLOC_CHECK_SIZE(_s) \
|
||||
do { \
|
||||
\
|
||||
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define ALLOC_CHECK_SIZE(_s) \
|
||||
do { \
|
||||
\
|
||||
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
|
||||
/* Macro to check malloc() failures and the like. */
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) \
|
||||
do { \
|
||||
\
|
||||
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define ALLOC_CHECK_RESULT(_r, _s) \
|
||||
do { \
|
||||
\
|
||||
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
||||
\
|
||||
} while (0)
|
||||
/* Magic tokens used to mark used / freed chunks. */
|
||||
|
||||
/* Magic tokens used to mark used / freed chunks. */
|
||||
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
|
||||
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
|
||||
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
|
||||
|
||||
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
|
||||
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
|
||||
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
|
||||
/* Positions of guard tokens in relation to the user-visible pointer. */
|
||||
|
||||
/* Positions of guard tokens in relation to the user-visible pointer. */
|
||||
#define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
|
||||
#define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
|
||||
#define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
|
||||
|
||||
#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
|
||||
#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
|
||||
#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
|
||||
#define ALLOC_OFF_HEAD 8
|
||||
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
|
||||
|
||||
#define ALLOC_OFF_HEAD 8
|
||||
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
|
||||
/* Allocator increments for ck_realloc_block(). */
|
||||
#define ALLOC_BLK_INC 256
|
||||
|
||||
#define ALLOC_BLK_INC 256
|
||||
/* Sanity-checking macros for pointers. */
|
||||
|
||||
/* Sanity-checking macros for pointers. */
|
||||
#define CHECK_PTR(_p) \
|
||||
do { \
|
||||
\
|
||||
if (_p) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
|
||||
ABORT("Use after free."); \
|
||||
else \
|
||||
ABORT("Corrupted head alloc canary."); \
|
||||
\
|
||||
} \
|
||||
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
|
||||
ABORT("Corrupted tail alloc canary."); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PTR(_p) \
|
||||
do { \
|
||||
\
|
||||
if (_p) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
|
||||
\
|
||||
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
|
||||
ABORT("Use after free."); \
|
||||
else \
|
||||
ABORT("Corrupted head alloc canary."); \
|
||||
\
|
||||
} \
|
||||
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
|
||||
ABORT("Corrupted tail alloc canary."); \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PTR_EXPR(_p) \
|
||||
({ \
|
||||
\
|
||||
typeof(_p) _tmp = (_p); \
|
||||
CHECK_PTR(_tmp); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
#define CHECK_PTR_EXPR(_p) \
|
||||
({ \
|
||||
\
|
||||
typeof(_p) _tmp = (_p); \
|
||||
CHECK_PTR(_tmp); \
|
||||
_tmp; \
|
||||
\
|
||||
})
|
||||
|
||||
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
|
||||
requests. */
|
||||
|
||||
static inline void* DFL_ck_alloc_nozero(u32 size) {
|
||||
static inline void *DFL_ck_alloc_nozero(u32 size) {
|
||||
|
||||
void* ret;
|
||||
void *ret;
|
||||
|
||||
if (!size) return NULL;
|
||||
|
||||
@ -333,9 +338,9 @@ static inline void* DFL_ck_alloc_nozero(u32 size) {
|
||||
|
||||
/* Allocate a buffer, returning zeroed memory. */
|
||||
|
||||
static inline void* DFL_ck_alloc(u32 size) {
|
||||
static inline void *DFL_ck_alloc(u32 size) {
|
||||
|
||||
void* mem;
|
||||
void *mem;
|
||||
|
||||
if (!size) return NULL;
|
||||
mem = DFL_ck_alloc_nozero(size);
|
||||
@ -347,18 +352,17 @@ static inline void* DFL_ck_alloc(u32 size) {
|
||||
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
||||
is set, the old memory will be also clobbered with 0xFF. */
|
||||
|
||||
static inline void DFL_ck_free(void* mem) {
|
||||
static inline void DFL_ck_free(void *mem) {
|
||||
|
||||
if (!mem) return;
|
||||
|
||||
CHECK_PTR(mem);
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
#ifdef DEBUG_BUILD
|
||||
|
||||
/* Catch pointer issues sooner. */
|
||||
memset(mem, 0xFF, ALLOC_S(mem));
|
||||
|
||||
#endif /* DEBUG_BUILD */
|
||||
#endif /* DEBUG_BUILD */
|
||||
|
||||
ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
||||
|
||||
@ -370,10 +374,10 @@ static inline void DFL_ck_free(void* mem) {
|
||||
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
|
||||
old memory is clobbered with 0xFF. */
|
||||
|
||||
static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
static inline void *DFL_ck_realloc(void *orig, u32 size) {
|
||||
|
||||
void* ret;
|
||||
u32 old_size = 0;
|
||||
void *ret;
|
||||
u32 old_size = 0;
|
||||
|
||||
if (!size) {
|
||||
|
||||
@ -386,9 +390,9 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
CHECK_PTR(orig);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
#ifndef DEBUG_BUILD
|
||||
ALLOC_C1(orig) = ALLOC_MAGIC_F;
|
||||
#endif /* !DEBUG_BUILD */
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
old_size = ALLOC_S(orig);
|
||||
orig -= ALLOC_OFF_HEAD;
|
||||
@ -399,12 +403,12 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
|
||||
ALLOC_CHECK_RESULT(ret, size);
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
/* Catch pointer issues sooner: force relocation and make sure that the
|
||||
original buffer is wiped. */
|
||||
@ -423,7 +427,7 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
ret += ALLOC_OFF_HEAD;
|
||||
|
||||
@ -440,9 +444,9 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
||||
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
|
||||
repeated small reallocs without complicating the user code). */
|
||||
|
||||
static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
if (orig) {
|
||||
|
||||
@ -454,7 +458,7 @@ static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
|
||||
}
|
||||
|
||||
#endif /* !DEBUG_BUILD */
|
||||
#endif /* !DEBUG_BUILD */
|
||||
|
||||
return DFL_ck_realloc(orig, size);
|
||||
|
||||
@ -462,14 +466,14 @@ static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
||||
|
||||
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_strdup(u8* str) {
|
||||
static inline u8 *DFL_ck_strdup(u8 *str) {
|
||||
|
||||
void* ret;
|
||||
u32 size;
|
||||
void *ret;
|
||||
u32 size;
|
||||
|
||||
if (!str) return NULL;
|
||||
|
||||
size = strlen((char*)str) + 1;
|
||||
size = strlen((char *)str) + 1;
|
||||
|
||||
ALLOC_CHECK_SIZE(size);
|
||||
ret = malloc(size + ALLOC_OFF_TOTAL);
|
||||
@ -488,9 +492,9 @@ static inline u8* DFL_ck_strdup(u8* str) {
|
||||
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
||||
or NULL inputs. */
|
||||
|
||||
static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
||||
static inline void *DFL_ck_memdup(void *mem, u32 size) {
|
||||
|
||||
void* ret;
|
||||
void *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
@ -511,9 +515,9 @@ static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
||||
/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
||||
Returns NULL for zero-sized or NULL inputs. */
|
||||
|
||||
static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
|
||||
|
||||
u8* ret;
|
||||
u8 *ret;
|
||||
|
||||
if (!mem || !size) return NULL;
|
||||
|
||||
@ -534,62 +538,62 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
||||
|
||||
}
|
||||
|
||||
#ifndef DEBUG_BUILD
|
||||
#ifndef DEBUG_BUILD
|
||||
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above functions
|
||||
to user-visible names such as ck_alloc(). */
|
||||
/* In non-debug mode, we just do straightforward aliasing of the above
|
||||
functions to user-visible names such as ck_alloc(). */
|
||||
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
#define ck_alloc DFL_ck_alloc
|
||||
#define ck_alloc_nozero DFL_ck_alloc_nozero
|
||||
#define ck_realloc DFL_ck_realloc
|
||||
#define ck_realloc_block DFL_ck_realloc_block
|
||||
#define ck_strdup DFL_ck_strdup
|
||||
#define ck_memdup DFL_ck_memdup
|
||||
#define ck_memdup_str DFL_ck_memdup_str
|
||||
#define ck_free DFL_ck_free
|
||||
|
||||
#define alloc_report()
|
||||
#define alloc_report()
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
/* In debugging mode, we also track allocations to detect memory leaks, and the
|
||||
flow goes through one more layer of indirection. */
|
||||
/* In debugging mode, we also track allocations to detect memory leaks, and
|
||||
the flow goes through one more layer of indirection. */
|
||||
|
||||
/* Alloc tracking data structures: */
|
||||
/* Alloc tracking data structures: */
|
||||
|
||||
#define ALLOC_BUCKETS 4096
|
||||
#define ALLOC_BUCKETS 4096
|
||||
|
||||
struct TRK_obj {
|
||||
|
||||
void* ptr;
|
||||
void *ptr;
|
||||
char *file, *func;
|
||||
u32 line;
|
||||
|
||||
};
|
||||
|
||||
#ifdef AFL_MAIN
|
||||
#ifdef AFL_MAIN
|
||||
|
||||
struct TRK_obj* TRK[ALLOC_BUCKETS];
|
||||
struct TRK_obj *TRK[ALLOC_BUCKETS];
|
||||
u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
#define alloc_report() TRK_report()
|
||||
#define alloc_report() TRK_report()
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
extern struct TRK_obj* TRK[ALLOC_BUCKETS];
|
||||
extern struct TRK_obj *TRK[ALLOC_BUCKETS];
|
||||
extern u32 TRK_cnt[ALLOC_BUCKETS];
|
||||
|
||||
#define alloc_report()
|
||||
#define alloc_report()
|
||||
|
||||
#endif /* ^AFL_MAIN */
|
||||
#endif /* ^AFL_MAIN */
|
||||
|
||||
/* Bucket-assigning function for a given pointer: */
|
||||
/* Bucket-assigning function for a given pointer: */
|
||||
|
||||
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
|
||||
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
|
||||
|
||||
/* Add a new entry to the list of allocated objects. */
|
||||
|
||||
static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
||||
static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
@ -605,8 +609,8 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
||||
if (!TRK[bucket][i].ptr) {
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char*)file;
|
||||
TRK[bucket][i].func = (char*)func;
|
||||
TRK[bucket][i].file = (char *)file;
|
||||
TRK[bucket][i].func = (char *)func;
|
||||
TRK[bucket][i].line = line;
|
||||
return;
|
||||
|
||||
@ -618,8 +622,8 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
||||
TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
|
||||
|
||||
TRK[bucket][i].ptr = ptr;
|
||||
TRK[bucket][i].file = (char*)file;
|
||||
TRK[bucket][i].func = (char*)func;
|
||||
TRK[bucket][i].file = (char *)file;
|
||||
TRK[bucket][i].func = (char *)func;
|
||||
TRK[bucket][i].line = line;
|
||||
|
||||
TRK_cnt[bucket]++;
|
||||
@ -628,7 +632,7 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
||||
|
||||
/* Remove entry from the list of allocated objects. */
|
||||
|
||||
static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
|
||||
static inline void TRK_free_buf(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
u32 i, bucket;
|
||||
@ -671,63 +675,63 @@ static inline void TRK_report(void) {
|
||||
|
||||
/* Simple wrappers for non-debugging functions: */
|
||||
|
||||
static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
|
||||
static inline void *TRK_ck_alloc(u32 size, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
void* ret = DFL_ck_alloc(size);
|
||||
void *ret = DFL_ck_alloc(size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_realloc(orig, size);
|
||||
void *ret = DFL_ck_realloc(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
static inline void *TRK_ck_realloc_block(void *orig, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_realloc_block(orig, size);
|
||||
void *ret = DFL_ck_realloc_block(orig, size);
|
||||
TRK_free_buf(orig, file, func, line);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
|
||||
static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
void* ret = DFL_ck_strdup(str);
|
||||
void *ret = DFL_ck_strdup(str);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
static inline void *TRK_ck_memdup(void *mem, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_memdup(mem, size);
|
||||
void *ret = DFL_ck_memdup(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
|
||||
const char* func, u32 line) {
|
||||
static inline void *TRK_ck_memdup_str(void *mem, u32 size, const char *file,
|
||||
const char *func, u32 line) {
|
||||
|
||||
void* ret = DFL_ck_memdup_str(mem, size);
|
||||
void *ret = DFL_ck_memdup_str(mem, size);
|
||||
TRK_alloc_buf(ret, file, func, line);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static inline void TRK_ck_free(void* ptr, const char* file, const char* func,
|
||||
static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
|
||||
u32 line) {
|
||||
|
||||
TRK_free_buf(ptr, file, func, line);
|
||||
@ -735,31 +739,130 @@ static inline void TRK_ck_free(void* ptr, const char* file, const char* func,
|
||||
|
||||
}
|
||||
|
||||
/* Aliasing user-facing names to tracking functions: */
|
||||
/* Aliasing user-facing names to tracking functions: */
|
||||
|
||||
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_alloc_nozero(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_alloc_nozero(_p1) \
|
||||
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc(_p1, _p2) \
|
||||
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_realloc(_p1, _p2) \
|
||||
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_realloc_block(_p1, _p2) \
|
||||
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_realloc_block(_p1, _p2) \
|
||||
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup(_p1, _p2) \
|
||||
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_memdup(_p1, _p2) \
|
||||
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_memdup_str(_p1, _p2) \
|
||||
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_memdup_str(_p1, _p2) \
|
||||
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
|
||||
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
#endif /* ^!DEBUG_BUILD */
|
||||
|
||||
#endif /* _WANT_ORIGINAL_AFL_ALLOC */
|
||||
|
||||
/* This function calculates the next power of 2 greater or equal its argument.
|
||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
||||
*/
|
||||
static inline size_t next_pow2(size_t in) {
|
||||
|
||||
if (in == 0 || in > (size_t)-1) {
|
||||
|
||||
return 0; /* avoid undefined behaviour under-/overflow */
|
||||
|
||||
}
|
||||
|
||||
size_t out = in - 1;
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
return out + 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(size_needed && *size >= size_needed)) { return *buf; }
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow and zero size_needed */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = realloc(*buf, next_size);
|
||||
*size = *buf ? next_size : 0;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* This function makes sure *size is > size_needed after call.
|
||||
It will realloc *buf otherwise.
|
||||
*size will grow exponentially as per:
|
||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
||||
Will FATAL if size_needed is <1.
|
||||
@return For convenience, this function returns *buf.
|
||||
*/
|
||||
static inline void *ck_maybe_grow(void **buf, size_t *size,
|
||||
size_t size_needed) {
|
||||
|
||||
/* Oops. found a bug? */
|
||||
if (unlikely(size_needed < 1)) { FATAL("cannot grow to non-positive size"); }
|
||||
|
||||
/* No need to realloc */
|
||||
if (likely(*size >= size_needed)) { return *buf; }
|
||||
|
||||
/* No initial size was set */
|
||||
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
|
||||
|
||||
/* grow exponentially */
|
||||
size_t next_size = next_pow2(size_needed);
|
||||
|
||||
/* handle overflow */
|
||||
if (!next_size) { next_size = size_needed; }
|
||||
|
||||
/* alloc */
|
||||
*buf = ck_realloc(*buf, next_size);
|
||||
*size = next_size;
|
||||
|
||||
return *buf;
|
||||
|
||||
}
|
||||
|
||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
||||
static inline void swap_bufs(void **buf1, size_t *size1, void **buf2,
|
||||
size_t *size2) {
|
||||
|
||||
void * scratch_buf = *buf1;
|
||||
size_t scratch_size = *size1;
|
||||
*buf1 = *buf2;
|
||||
*size1 = *size2;
|
||||
*buf2 = scratch_buf;
|
||||
*size2 = scratch_size;
|
||||
|
||||
}
|
||||
|
||||
#undef INITIAL_GROWTH_SIZE
|
||||
|
||||
#endif /* ! _HAVE_ALLOC_INL_H */
|
||||
|
||||
|
46
include/android-ashmem.h
Executable file → Normal file
46
include/android-ashmem.h
Executable file → Normal file
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -25,26 +26,29 @@
|
||||
#ifndef _ANDROID_ASHMEM_H
|
||||
#define _ANDROID_ASHMEM_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#if __ANDROID_API__ >= 26
|
||||
#define shmat bionic_shmat
|
||||
#define shmctl bionic_shmctl
|
||||
#define shmdt bionic_shmdt
|
||||
#define shmget bionic_shmget
|
||||
#endif
|
||||
#include <sys/shm.h>
|
||||
#undef shmat
|
||||
#undef shmctl
|
||||
#undef shmdt
|
||||
#undef shmget
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
#if __ANDROID_API__ >= 26
|
||||
#define shmat bionic_shmat
|
||||
#define shmctl bionic_shmctl
|
||||
#define shmdt bionic_shmdt
|
||||
#define shmget bionic_shmget
|
||||
#endif
|
||||
|
||||
#include <sys/shm.h>
|
||||
#undef shmat
|
||||
#undef shmctl
|
||||
#undef shmdt
|
||||
#undef shmget
|
||||
#include <stdio.h>
|
||||
|
||||
#define ASHMEM_DEVICE "/dev/ashmem"
|
||||
|
||||
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
|
||||
|
||||
@ -102,5 +106,7 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -28,6 +29,7 @@
|
||||
#define _AFL_CMPLOG_H
|
||||
|
||||
#include "config.h"
|
||||
#include "forkserver.h"
|
||||
|
||||
#define CMP_MAP_W 65536
|
||||
#define CMP_MAP_H 256
|
||||
@ -73,5 +75,9 @@ struct cmp_map {
|
||||
|
||||
};
|
||||
|
||||
/* Execs the child */
|
||||
|
||||
void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -25,14 +26,96 @@
|
||||
|
||||
#ifndef __AFLCOMMON_H
|
||||
#define __AFLCOMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "types.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
extern u8* target_path; /* Path to target binary */
|
||||
/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
|
||||
|
||||
void detect_file_args(char** argv, u8* prog_in);
|
||||
void check_environment_vars(char** env);
|
||||
#define STRINGIFY_VAL_SIZE_MAX (16)
|
||||
|
||||
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin);
|
||||
void check_environment_vars(char **env);
|
||||
|
||||
char **argv_cpy_dup(int argc, char **argv);
|
||||
void argv_cpy_free(char **argv);
|
||||
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char * get_afl_env(char *env);
|
||||
|
||||
extern u8 be_quiet;
|
||||
extern u8 *doc_path; /* path to documentation dir */
|
||||
|
||||
/* Find binary, used by analyze, showmap, tmin
|
||||
@returns the path, allocating the string */
|
||||
|
||||
u8 *find_binary(u8 *fname);
|
||||
|
||||
/* Read a bitmap from file fname to memory
|
||||
This is for the -B option again. */
|
||||
|
||||
void read_bitmap(u8 *fname, u8 *map, size_t len);
|
||||
|
||||
/* Get unix time in milliseconds */
|
||||
|
||||
u64 get_cur_time(void);
|
||||
|
||||
/* Get unix time in microseconds */
|
||||
|
||||
u64 get_cur_time_us(void);
|
||||
|
||||
/* Describe integer. The buf should be
|
||||
at least 6 bytes to fit all ints we randomly see.
|
||||
Will return buf for convenience. */
|
||||
|
||||
u8 *stringify_int(u8 *buf, size_t len, u64 val);
|
||||
|
||||
/* Describe float. Similar as int. */
|
||||
|
||||
u8 *stringify_float(u8 *buf, size_t len, double val);
|
||||
|
||||
/* Describe integer as memory size. */
|
||||
|
||||
u8 *stringify_mem_size(u8 *buf, size_t len, u64 val);
|
||||
|
||||
/* Describe time delta as string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Unsafe Describe integer. The buf sizes are not checked.
|
||||
This is unsafe but fast.
|
||||
Will return buf for convenience. */
|
||||
|
||||
u8 *u_stringify_int(u8 *buf, u64 val);
|
||||
|
||||
/* Unsafe describe float. Similar as unsafe int. */
|
||||
|
||||
u8 *u_stringify_float(u8 *buf, double val);
|
||||
|
||||
/* Unsafe describe integer as memory size. */
|
||||
|
||||
u8 *u_stringify_mem_size(u8 *buf, u64 val);
|
||||
|
||||
/* Unsafe describe time delta as string.
|
||||
Returns a pointer to buf for convenience. */
|
||||
|
||||
u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
|
||||
|
||||
/* Wrapper for select() and read(), reading exactly len bytes.
|
||||
Returns the time passed to read.
|
||||
stop_soon should point to a variable indicating ctrl+c was pressed.
|
||||
If the wait times out, returns timeout_ms + 1;
|
||||
Returns 0 if an error occurred (fd closed, signal, ...); */
|
||||
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
|
||||
volatile u8 *stop_soon_p);
|
||||
|
||||
u32 get_map_size(void);
|
||||
|
||||
char** get_qemu_argv(u8* own_loc, char** argv, int argc);
|
||||
char** get_wine_argv(u8* own_loc, char** argv, int argc);
|
||||
#endif
|
||||
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,7 +28,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++2.62c"
|
||||
#define VERSION "++2.65c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -48,7 +49,7 @@
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
|
||||
#define FANCY_BOXES
|
||||
#define FANCY_BOXES
|
||||
#endif
|
||||
|
||||
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||
@ -62,20 +63,20 @@
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||
#define WORD_SIZE_64 1
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
/* Default memory limit for child process (MB): */
|
||||
|
||||
#ifndef __NetBSD__
|
||||
#ifndef WORD_SIZE_64
|
||||
#define MEM_LIMIT 25
|
||||
#else
|
||||
#define MEM_LIMIT 50
|
||||
#endif /* ^!WORD_SIZE_64 */
|
||||
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
|
||||
#165 */
|
||||
#define MEM_LIMIT 200
|
||||
#ifndef WORD_SIZE_64
|
||||
#define MEM_LIMIT 25
|
||||
#else
|
||||
#define MEM_LIMIT 50
|
||||
#endif /* ^!WORD_SIZE_64 */
|
||||
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
|
||||
#165 */
|
||||
#define MEM_LIMIT 200
|
||||
#endif
|
||||
/* Default memory limit when running in QEMU mode (MB): */
|
||||
|
||||
@ -200,8 +201,8 @@
|
||||
(first value), and to keep in memory as candidates. The latter should be much
|
||||
higher than the former. */
|
||||
|
||||
#define USE_AUTO_EXTRAS 50
|
||||
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
|
||||
#define USE_AUTO_EXTRAS 128
|
||||
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64)
|
||||
|
||||
/* Scaling factor for the effector map used to skip some of the more
|
||||
expensive deterministic steps. The actual divisor is set to
|
||||
@ -394,9 +395,9 @@
|
||||
|
||||
/* for *BSD: use ARC4RANDOM and save a file descriptor */
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
#define HAVE_ARC4RANDOM 1
|
||||
#endif
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
#define HAVE_ARC4RANDOM 1
|
||||
#endif
|
||||
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
|
||||
|
||||
#endif /* ! _HAVE_CONFIG_H */
|
||||
|
210
include/debug.h
210
include/debug.h
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,83 +28,92 @@
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
|
||||
/* __FUNCTION__ is non-iso */
|
||||
#ifdef __func__
|
||||
#define __FUNCTION__ __func__
|
||||
#endif
|
||||
|
||||
/*******************
|
||||
* Terminal colors *
|
||||
*******************/
|
||||
|
||||
#ifndef MESSAGES_TO_STDOUT
|
||||
#define MESSAGES_TO_STDOUT
|
||||
#endif
|
||||
|
||||
#ifdef USE_COLOR
|
||||
|
||||
#define cBLK "\x1b[0;30m"
|
||||
#define cRED "\x1b[0;31m"
|
||||
#define cGRN "\x1b[0;32m"
|
||||
#define cBRN "\x1b[0;33m"
|
||||
#define cBLU "\x1b[0;34m"
|
||||
#define cMGN "\x1b[0;35m"
|
||||
#define cCYA "\x1b[0;36m"
|
||||
#define cLGR "\x1b[0;37m"
|
||||
#define cGRA "\x1b[1;90m"
|
||||
#define cLRD "\x1b[1;91m"
|
||||
#define cLGN "\x1b[1;92m"
|
||||
#define cYEL "\x1b[1;93m"
|
||||
#define cLBL "\x1b[1;94m"
|
||||
#define cPIN "\x1b[1;95m"
|
||||
#define cLCY "\x1b[1;96m"
|
||||
#define cBRI "\x1b[1;97m"
|
||||
#define cRST "\x1b[0m"
|
||||
#define cBLK "\x1b[0;30m"
|
||||
#define cRED "\x1b[0;31m"
|
||||
#define cGRN "\x1b[0;32m"
|
||||
#define cBRN "\x1b[0;33m"
|
||||
#define cBLU "\x1b[0;34m"
|
||||
#define cMGN "\x1b[0;35m"
|
||||
#define cCYA "\x1b[0;36m"
|
||||
#define cLGR "\x1b[0;37m"
|
||||
#define cGRA "\x1b[1;90m"
|
||||
#define cLRD "\x1b[1;91m"
|
||||
#define cLGN "\x1b[1;92m"
|
||||
#define cYEL "\x1b[1;93m"
|
||||
#define cLBL "\x1b[1;94m"
|
||||
#define cPIN "\x1b[1;95m"
|
||||
#define cLCY "\x1b[1;96m"
|
||||
#define cBRI "\x1b[1;97m"
|
||||
#define cRST "\x1b[0m"
|
||||
|
||||
#define bgBLK "\x1b[40m"
|
||||
#define bgRED "\x1b[41m"
|
||||
#define bgGRN "\x1b[42m"
|
||||
#define bgBRN "\x1b[43m"
|
||||
#define bgBLU "\x1b[44m"
|
||||
#define bgMGN "\x1b[45m"
|
||||
#define bgCYA "\x1b[46m"
|
||||
#define bgLGR "\x1b[47m"
|
||||
#define bgGRA "\x1b[100m"
|
||||
#define bgLRD "\x1b[101m"
|
||||
#define bgLGN "\x1b[102m"
|
||||
#define bgYEL "\x1b[103m"
|
||||
#define bgLBL "\x1b[104m"
|
||||
#define bgPIN "\x1b[105m"
|
||||
#define bgLCY "\x1b[106m"
|
||||
#define bgBRI "\x1b[107m"
|
||||
#define bgBLK "\x1b[40m"
|
||||
#define bgRED "\x1b[41m"
|
||||
#define bgGRN "\x1b[42m"
|
||||
#define bgBRN "\x1b[43m"
|
||||
#define bgBLU "\x1b[44m"
|
||||
#define bgMGN "\x1b[45m"
|
||||
#define bgCYA "\x1b[46m"
|
||||
#define bgLGR "\x1b[47m"
|
||||
#define bgGRA "\x1b[100m"
|
||||
#define bgLRD "\x1b[101m"
|
||||
#define bgLGN "\x1b[102m"
|
||||
#define bgYEL "\x1b[103m"
|
||||
#define bgLBL "\x1b[104m"
|
||||
#define bgPIN "\x1b[105m"
|
||||
#define bgLCY "\x1b[106m"
|
||||
#define bgBRI "\x1b[107m"
|
||||
|
||||
#else
|
||||
|
||||
#define cBLK ""
|
||||
#define cRED ""
|
||||
#define cGRN ""
|
||||
#define cBRN ""
|
||||
#define cBLU ""
|
||||
#define cMGN ""
|
||||
#define cCYA ""
|
||||
#define cLGR ""
|
||||
#define cGRA ""
|
||||
#define cLRD ""
|
||||
#define cLGN ""
|
||||
#define cYEL ""
|
||||
#define cLBL ""
|
||||
#define cPIN ""
|
||||
#define cLCY ""
|
||||
#define cBRI ""
|
||||
#define cRST ""
|
||||
#define cBLK ""
|
||||
#define cRED ""
|
||||
#define cGRN ""
|
||||
#define cBRN ""
|
||||
#define cBLU ""
|
||||
#define cMGN ""
|
||||
#define cCYA ""
|
||||
#define cLGR ""
|
||||
#define cGRA ""
|
||||
#define cLRD ""
|
||||
#define cLGN ""
|
||||
#define cYEL ""
|
||||
#define cLBL ""
|
||||
#define cPIN ""
|
||||
#define cLCY ""
|
||||
#define cBRI ""
|
||||
#define cRST ""
|
||||
|
||||
#define bgBLK ""
|
||||
#define bgRED ""
|
||||
#define bgGRN ""
|
||||
#define bgBRN ""
|
||||
#define bgBLU ""
|
||||
#define bgMGN ""
|
||||
#define bgCYA ""
|
||||
#define bgLGR ""
|
||||
#define bgGRA ""
|
||||
#define bgLRD ""
|
||||
#define bgLGN ""
|
||||
#define bgYEL ""
|
||||
#define bgLBL ""
|
||||
#define bgPIN ""
|
||||
#define bgLCY ""
|
||||
#define bgBRI ""
|
||||
#define bgBLK ""
|
||||
#define bgRED ""
|
||||
#define bgGRN ""
|
||||
#define bgBRN ""
|
||||
#define bgBLU ""
|
||||
#define bgMGN ""
|
||||
#define bgCYA ""
|
||||
#define bgLGR ""
|
||||
#define bgGRA ""
|
||||
#define bgLRD ""
|
||||
#define bgLGN ""
|
||||
#define bgYEL ""
|
||||
#define bgLBL ""
|
||||
#define bgPIN ""
|
||||
#define bgLCY ""
|
||||
#define bgBRI ""
|
||||
|
||||
#endif /* ^USE_COLOR */
|
||||
|
||||
@ -113,39 +123,39 @@
|
||||
|
||||
#ifdef FANCY_BOXES
|
||||
|
||||
#define SET_G1 "\x1b)0" /* Set G1 for box drawing */
|
||||
#define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
|
||||
#define bSTART "\x0e" /* Enter G1 drawing mode */
|
||||
#define bSTOP "\x0f" /* Leave G1 drawing mode */
|
||||
#define bH "q" /* Horizontal line */
|
||||
#define bV "x" /* Vertical line */
|
||||
#define bLT "l" /* Left top corner */
|
||||
#define bRT "k" /* Right top corner */
|
||||
#define bLB "m" /* Left bottom corner */
|
||||
#define bRB "j" /* Right bottom corner */
|
||||
#define bX "n" /* Cross */
|
||||
#define bVR "t" /* Vertical, branch right */
|
||||
#define bVL "u" /* Vertical, branch left */
|
||||
#define bHT "v" /* Horizontal, branch top */
|
||||
#define bHB "w" /* Horizontal, branch bottom */
|
||||
#define SET_G1 "\x1b)0" /* Set G1 for box drawing */
|
||||
#define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
|
||||
#define bSTART "\x0e" /* Enter G1 drawing mode */
|
||||
#define bSTOP "\x0f" /* Leave G1 drawing mode */
|
||||
#define bH "q" /* Horizontal line */
|
||||
#define bV "x" /* Vertical line */
|
||||
#define bLT "l" /* Left top corner */
|
||||
#define bRT "k" /* Right top corner */
|
||||
#define bLB "m" /* Left bottom corner */
|
||||
#define bRB "j" /* Right bottom corner */
|
||||
#define bX "n" /* Cross */
|
||||
#define bVR "t" /* Vertical, branch right */
|
||||
#define bVL "u" /* Vertical, branch left */
|
||||
#define bHT "v" /* Horizontal, branch top */
|
||||
#define bHB "w" /* Horizontal, branch bottom */
|
||||
|
||||
#else
|
||||
|
||||
#define SET_G1 ""
|
||||
#define RESET_G1 ""
|
||||
#define bSTART ""
|
||||
#define bSTOP ""
|
||||
#define bH "-"
|
||||
#define bV "|"
|
||||
#define bLT "+"
|
||||
#define bRT "+"
|
||||
#define bLB "+"
|
||||
#define bRB "+"
|
||||
#define bX "+"
|
||||
#define bVR "+"
|
||||
#define bVL "+"
|
||||
#define bHT "+"
|
||||
#define bHB "+"
|
||||
#define SET_G1 ""
|
||||
#define RESET_G1 ""
|
||||
#define bSTART ""
|
||||
#define bSTOP ""
|
||||
#define bH "-"
|
||||
#define bV "|"
|
||||
#define bLT "+"
|
||||
#define bRT "+"
|
||||
#define bLB "+"
|
||||
#define bRB "+"
|
||||
#define bX "+"
|
||||
#define bVR "+"
|
||||
#define bVL "+"
|
||||
#define bHT "+"
|
||||
#define bHB "+"
|
||||
|
||||
#endif /* ^FANCY_BOXES */
|
||||
|
||||
@ -166,9 +176,9 @@
|
||||
/* Just print stuff to the appropriate stream. */
|
||||
|
||||
#ifdef MESSAGES_TO_STDOUT
|
||||
#define SAYF(x...) printf(x)
|
||||
#define SAYF(x...) printf(x)
|
||||
#else
|
||||
#define SAYF(x...) fprintf(stderr, x)
|
||||
#define SAYF(x...) fprintf(stderr, x)
|
||||
#endif /* ^MESSAGES_TO_STDOUT */
|
||||
|
||||
/* Show a prefixed warning. */
|
||||
|
@ -1,97 +1,3 @@
|
||||
const char *afl_environment_variables[] = {
|
||||
|
||||
"AFL_ALIGNED_ALLOC",
|
||||
"AFL_ALLOW_TMP",
|
||||
"AFL_ANALYZE_HEX",
|
||||
"AFL_AS",
|
||||
"AFL_AS_FORCE_INSTRUMENT",
|
||||
"AFL_BENCH_JUST_ONE",
|
||||
"AFL_BENCH_UNTIL_CRASH",
|
||||
"AFL_CAL_FAST",
|
||||
"AFL_CC",
|
||||
"AFL_CMIN_ALLOW_ANY",
|
||||
"AFL_CMIN_CRASHES_ONLY",
|
||||
"AFL_CODE_END",
|
||||
"AFL_CODE_START",
|
||||
"AFL_COMPCOV_BINNAME",
|
||||
"AFL_COMPCOV_LEVEL",
|
||||
"AFL_CUSTOM_MUTATOR_LIBRARY",
|
||||
"AFL_CUSTOM_MUTATOR_ONLY",
|
||||
"AFL_CXX",
|
||||
"AFL_DEBUG",
|
||||
"AFL_DEBUG_CHILD_OUTPUT",
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_DISABLE_TRIM",
|
||||
"AFL_DONT_OPTIMIZE",
|
||||
"AFL_DUMB_FORKSRV",
|
||||
"AFL_ENTRYPOINT",
|
||||
"AFL_EXIT_WHEN_DONE",
|
||||
"AFL_FAST_CAL",
|
||||
"AFL_FORCE_UI",
|
||||
"AFL_GCC_WHITELIST",
|
||||
"AFL_GCJ",
|
||||
"AFL_HANG_TMOUT",
|
||||
"AFL_HARDEN",
|
||||
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
|
||||
"AFL_IMPORT_FIRST",
|
||||
"AFL_INST_LIBS",
|
||||
"AFL_INST_RATIO",
|
||||
"AFL_KEEP_TRACES",
|
||||
"AFL_KEEP_ASSEMBLY",
|
||||
"AFL_LD_HARD_FAIL",
|
||||
"AFL_LD_LIMIT_MB",
|
||||
"AFL_LD_NO_CALLOC_OVER",
|
||||
"AFL_LD_PRELOAD",
|
||||
"AFL_LD_VERBOSE",
|
||||
"AFL_LLVM_CMPLOG",
|
||||
"AFL_LLVM_INSTRIM",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES",
|
||||
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
|
||||
"AFL_LLVM_LAF_SPLIT_FLOATS",
|
||||
"AFL_LLVM_LAF_SPLIT_SWITCHES",
|
||||
"AFL_LLVM_LAF_TRANSFORM_COMPARES",
|
||||
"AFL_LLVM_NOT_ZERO",
|
||||
"AFL_LLVM_WHITELIST",
|
||||
"AFL_NO_AFFINITY",
|
||||
"AFL_NO_ARITH",
|
||||
"AFL_NO_BUILTIN",
|
||||
"AFL_NO_CPU_RED",
|
||||
"AFL_NO_FORKSRV",
|
||||
"AFL_NO_UI",
|
||||
"AFL_NO_X86", // not really an env but we dont want to warn on it
|
||||
"AFL_PATH",
|
||||
"AFL_PERFORMANCE_FILE",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PRELOAD",
|
||||
"AFL_PYTHON_MODULE",
|
||||
"AFL_PYTHON_ONLY",
|
||||
"AFL_QEMU_COMPCOV",
|
||||
"AFL_QEMU_COMPCOV_DEBUG",
|
||||
"AFL_QEMU_DEBUG_MAPS",
|
||||
"AFL_QEMU_DISABLE_CACHE",
|
||||
"AFL_QEMU_PERSISTENT_ADDR",
|
||||
"AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR",
|
||||
"AFL_QEMU_PERSISTENT_HOOK",
|
||||
"AFL_QEMU_PERSISTENT_RET",
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
|
||||
"AFL_QUIET",
|
||||
"AFL_RANDOM_ALLOC_CANARY",
|
||||
"AFL_REAL_PATH",
|
||||
"AFL_SHUFFLE_QUEUE",
|
||||
"AFL_SKIP_BIN_CHECK",
|
||||
"AFL_SKIP_CPUFREQ",
|
||||
"AFL_SKIP_CRASHES",
|
||||
"AFL_TMIN_EXACT",
|
||||
"AFL_TMPDIR",
|
||||
"AFL_TOKEN_FILE",
|
||||
"AFL_TRACE_PC",
|
||||
"AFL_USE_ASAN",
|
||||
"AFL_USE_MSAN",
|
||||
"AFL_USE_TRACE_PC",
|
||||
"AFL_USE_UBSAN",
|
||||
"AFL_WINE_PATH",
|
||||
NULL};
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -7,8 +7,9 @@
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,24 +28,102 @@
|
||||
#ifndef __AFL_FORKSERVER_H
|
||||
#define __AFL_FORKSERVER_H
|
||||
|
||||
void handle_timeout(int sig);
|
||||
void init_forkserver(char **argv);
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct afl_forkserver {
|
||||
|
||||
/* a program that includes afl-forkserver needs to define these */
|
||||
|
||||
u8 uses_asan; /* Target uses ASAN? */
|
||||
u8 *trace_bits; /* SHM with instrumentation bitmap */
|
||||
u8 use_stdin; /* use stdin for sending data */
|
||||
|
||||
s32 fsrv_pid, /* PID of the fork server */
|
||||
child_pid, /* PID of the fuzzed program */
|
||||
child_status, /* waitpid result for the child */
|
||||
out_dir_fd; /* FD of the lock file */
|
||||
|
||||
s32 out_fd, /* Persistent fd for fsrv->out_file */
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
dev_urandom_fd, /* Persistent fd for /dev/urandom */
|
||||
#endif
|
||||
dev_null_fd, /* Persistent fd for /dev/null */
|
||||
fsrv_ctl_fd, /* Fork server control pipe (write) */
|
||||
fsrv_st_fd; /* Fork server status pipe (read) */
|
||||
|
||||
u8 no_unlink; /* do not unlink cur_input */
|
||||
|
||||
u32 exec_tmout; /* Configurable exec timeout (ms) */
|
||||
u32 map_size; /* map size used by the target */
|
||||
u32 snapshot; /* is snapshot feature used */
|
||||
u64 mem_limit; /* Memory cap for child (MB) */
|
||||
|
||||
u64 total_execs; /* How often run_target was called */
|
||||
|
||||
u8 *out_file, /* File to fuzz, if any */
|
||||
*target_path; /* Path of the target */
|
||||
|
||||
FILE *plot_file; /* Gnuplot output file */
|
||||
|
||||
/* Note: lat_run_timed_out is u32 to send it to the child as 4 byte array */
|
||||
u32 last_run_timed_out; /* Traced process timed out? */
|
||||
|
||||
u8 last_kill_signal; /* Signal that killed the child */
|
||||
|
||||
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
|
||||
|
||||
u8 qemu_mode; /* if running in qemu mode or not */
|
||||
|
||||
char *cmplog_binary; /* the name of the cmplog binary */
|
||||
|
||||
/* Function to kick off the forkserver child */
|
||||
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
u8 *function_opt; /* for autodictionary: afl ptr */
|
||||
|
||||
void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len);
|
||||
|
||||
} afl_forkserver_t;
|
||||
|
||||
typedef enum fsrv_run_result {
|
||||
|
||||
/* 00 */ FSRV_RUN_OK = 0,
|
||||
/* 01 */ FSRV_RUN_TMOUT,
|
||||
/* 02 */ FSRV_RUN_CRASH,
|
||||
/* 03 */ FSRV_RUN_ERROR,
|
||||
/* 04 */ FSRV_RUN_NOINST,
|
||||
/* 05 */ FSRV_RUN_NOBITS,
|
||||
|
||||
} fsrv_run_result_t;
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len);
|
||||
fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
|
||||
volatile u8 *stop_soon_p);
|
||||
void afl_fsrv_killall(void);
|
||||
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define MSG_FORK_ON_APPLE \
|
||||
" - On MacOS X, the semantics of fork() syscalls are non-standard and " \
|
||||
"may\n" \
|
||||
" break afl-fuzz performance optimizations when running " \
|
||||
"platform-specific\n" \
|
||||
" targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
|
||||
#define MSG_FORK_ON_APPLE \
|
||||
" - On MacOS X, the semantics of fork() syscalls are non-standard and " \
|
||||
"may\n" \
|
||||
" break afl-fuzz performance optimizations when running " \
|
||||
"platform-specific\n" \
|
||||
" targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
|
||||
#else
|
||||
#define MSG_FORK_ON_APPLE ""
|
||||
#define MSG_FORK_ON_APPLE ""
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_AS
|
||||
#define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
|
||||
#define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
|
||||
#else
|
||||
#define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
|
||||
#define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
|
||||
#endif /* ^RLIMIT_AS */
|
||||
|
||||
#endif
|
||||
|
@ -32,11 +32,11 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void* key, u32 len, u32 seed) {
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u64* data = (u64*)key;
|
||||
const u64 *data = (u64 *)key;
|
||||
u64 h1 = seed ^ len;
|
||||
|
||||
len >>= 3;
|
||||
@ -67,11 +67,11 @@ static inline u32 hash32(const void* key, u32 len, u32 seed) {
|
||||
|
||||
#else
|
||||
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void* key, u32 len, u32 seed) {
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u32* data = (u32*)key;
|
||||
const u32 *data = (u32 *)key;
|
||||
u32 h1 = seed ^ len;
|
||||
|
||||
len >>= 2;
|
||||
|
182
include/list.h
Normal file
182
include/list.h
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
american fuzzy lop++ - linked list code
|
||||
---------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This allocator is not designed to resist malicious attackers (the canaries
|
||||
are small and predictable), but provides a robust and portable way to detect
|
||||
use-after-free, off-by-one writes, stale pointers, and so on.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef AFL_LIST
|
||||
#define AFL_LIST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "afl-prealloc.h"
|
||||
|
||||
/* How many elements to allocate before malloc is needed */
|
||||
#define LIST_PREALLOC_SIZE (64)
|
||||
|
||||
typedef struct list_element {
|
||||
|
||||
PREALLOCABLE;
|
||||
|
||||
struct list_element *prev;
|
||||
struct list_element *next;
|
||||
void * data;
|
||||
|
||||
} element_t;
|
||||
|
||||
typedef struct list {
|
||||
|
||||
element_t element_prealloc_buf[LIST_PREALLOC_SIZE];
|
||||
s32 element_prealloc_count;
|
||||
|
||||
} list_t;
|
||||
|
||||
static inline element_t *get_head(list_t *list) {
|
||||
|
||||
/* The first element is the head */
|
||||
return list->element_prealloc_buf;
|
||||
|
||||
}
|
||||
|
||||
static inline void list_free_el(list_t *list, element_t *el) {
|
||||
|
||||
PRE_FREE(el, list->element_prealloc_count);
|
||||
|
||||
}
|
||||
|
||||
static inline void list_append(list_t *list, void *el) {
|
||||
|
||||
element_t *head = get_head(list);
|
||||
if (!head->next) {
|
||||
|
||||
/* initialize */
|
||||
|
||||
memset(list, 0, sizeof(list_t));
|
||||
PRE_ALLOC_FORCE(head, list->element_prealloc_count);
|
||||
head->next = head->prev = head;
|
||||
|
||||
}
|
||||
|
||||
element_t *el_box = NULL;
|
||||
PRE_ALLOC(el_box, list->element_prealloc_buf, LIST_PREALLOC_SIZE,
|
||||
list->element_prealloc_count);
|
||||
if (!el_box) { FATAL("failed to allocate list element"); }
|
||||
el_box->data = el;
|
||||
el_box->next = head;
|
||||
el_box->prev = head->prev;
|
||||
head->prev->next = el_box;
|
||||
head->prev = el_box;
|
||||
|
||||
}
|
||||
|
||||
/* Simple foreach.
|
||||
Pointer to the current element is in `el`,
|
||||
casted to (a pointer) of the given `type`.
|
||||
A return from this block will return from calling func.
|
||||
*/
|
||||
|
||||
#define LIST_FOREACH(list, type, block) \
|
||||
do { \
|
||||
\
|
||||
list_t * li = (list); \
|
||||
element_t *head = get_head((li)); \
|
||||
element_t *el_box = (head)->next; \
|
||||
if (!el_box) FATAL("foreach over uninitialized list"); \
|
||||
while (el_box != head) { \
|
||||
\
|
||||
__attribute__((unused)) type *el = (type *)((el_box)->data); \
|
||||
/* get next so el_box can be unlinked */ \
|
||||
element_t *next = el_box->next; \
|
||||
{block}; \
|
||||
el_box = next; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* In foreach: remove the current el from the list */
|
||||
|
||||
#define LIST_REMOVE_CURRENT_EL_IN_FOREACH() \
|
||||
do { \
|
||||
\
|
||||
el_box->prev->next = next; \
|
||||
el_box->next->prev = el_box->prev; \
|
||||
list_free_el(li, el_box); \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* Same as foreach, but will clear list in the process */
|
||||
|
||||
#define LIST_FOREACH_CLEAR(list, type, block) \
|
||||
do { \
|
||||
\
|
||||
LIST_FOREACH((list), type, { \
|
||||
\
|
||||
{block}; \
|
||||
LIST_REMOVE_CURRENT_EL_IN_FOREACH(); \
|
||||
\
|
||||
}); \
|
||||
\
|
||||
} while (0);
|
||||
|
||||
/* remove an item from the list */
|
||||
|
||||
static inline void list_remove(list_t *list, void *remove_me) {
|
||||
|
||||
LIST_FOREACH(list, void, {
|
||||
|
||||
if (el == remove_me) {
|
||||
|
||||
el_box->prev->next = el_box->next;
|
||||
el_box->next->prev = el_box->prev;
|
||||
el_box->data = NULL;
|
||||
list_free_el(list, el_box);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
FATAL("List item to be removed not in list");
|
||||
|
||||
}
|
||||
|
||||
/* Returns true if el is in list */
|
||||
|
||||
static inline bool list_contains(list_t *list, void *contains_me) {
|
||||
|
||||
LIST_FOREACH(list, void, {
|
||||
|
||||
if (el == contains_me) return true;
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,8 +7,9 @@
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -27,11 +28,33 @@
|
||||
#ifndef __AFL_SHAREDMEM_H
|
||||
#define __AFL_SHAREDMEM_H
|
||||
|
||||
void setup_shm(unsigned char dumb_mode);
|
||||
void remove_shm(void);
|
||||
#include "types.h"
|
||||
|
||||
extern int cmplog_mode;
|
||||
extern struct cmp_map* cmp_map;
|
||||
typedef struct sharedmem {
|
||||
|
||||
// extern unsigned char *trace_bits;
|
||||
|
||||
#ifdef USEMMAP
|
||||
/* ================ Proteas ================ */
|
||||
int g_shm_fd;
|
||||
char g_shm_file_path[L_tmpnam];
|
||||
/* ========================================= */
|
||||
#else
|
||||
s32 shm_id; /* ID of the SHM region */
|
||||
s32 cmplog_shm_id;
|
||||
#endif
|
||||
|
||||
u8 *map; /* shared memory region */
|
||||
|
||||
size_t map_size; /* actual allocated size */
|
||||
|
||||
int cmplog_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
} sharedmem_t;
|
||||
|
||||
u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char dumb_mode);
|
||||
void afl_shm_deinit(sharedmem_t *);
|
||||
|
||||
#endif
|
||||
|
||||
|
59
include/snapshot-inl.h
Normal file
59
include/snapshot-inl.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
american fuzzy lop++ - snapshot helpers routines
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
// From AFL-Snapshot-LKM/include/afl_snapshot.h (must be kept synced)
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define AFL_SNAPSHOT_FILE_NAME "/dev/afl_snapshot"
|
||||
|
||||
#define AFL_SNAPSHOT_IOCTL_MAGIC 44313
|
||||
|
||||
#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1)
|
||||
#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2)
|
||||
|
||||
static int afl_snapshot_dev_fd;
|
||||
|
||||
static int afl_snapshot_init(void) {
|
||||
|
||||
afl_snapshot_dev_fd = open(AFL_SNAPSHOT_FILE_NAME, 0);
|
||||
return afl_snapshot_dev_fd;
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_do() {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO);
|
||||
|
||||
}
|
||||
|
||||
static int afl_snapshot_clean(void) {
|
||||
|
||||
return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN);
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,9 @@
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
@ -29,6 +30,29 @@ typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
/* Extended forkserver option values */
|
||||
|
||||
/* Reporting errors */
|
||||
#define FS_OPT_ERROR 0xf800008f
|
||||
#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
|
||||
#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
|
||||
#define FS_ERROR_MAP_SIZE 1
|
||||
#define FS_ERROR_MAP_ADDR 2
|
||||
#define FS_ERROR_SHM_OPEN 4
|
||||
#define FS_ERROR_SHMAT 8
|
||||
#define FS_ERROR_MMAP 16
|
||||
|
||||
/* Reporting options */
|
||||
#define FS_OPT_ENABLED 0x8f000001
|
||||
#define FS_OPT_MAPSIZE 0x40000000
|
||||
#define FS_OPT_SNAPSHOT 0x20000000
|
||||
#define FS_OPT_AUTODICT 0x10000000
|
||||
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
|
||||
#define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1)
|
||||
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
|
||||
#define FS_OPT_SET_MAPSIZE(x) \
|
||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||
|
||||
/*
|
||||
|
||||
Ugh. There is an unintended compiler / glibc #include glitch caused by
|
||||
@ -45,7 +69,7 @@ typedef uint32_t u32;
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __x86_64__
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
typedef unsigned long long u64;
|
||||
#else
|
||||
typedef uint64_t u64;
|
||||
@ -57,8 +81,24 @@ typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a))
|
||||
#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#define MAX(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#endif /* !MIN */
|
||||
|
||||
#define SWAP16(_x) \
|
||||
@ -93,21 +133,21 @@ typedef int64_t s64;
|
||||
})
|
||||
|
||||
#ifdef AFL_LLVM_PASS
|
||||
#if defined(__linux__)
|
||||
#define AFL_SR(s) (srandom(s))
|
||||
#define AFL_R(x) (random() % (x))
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define AFL_SR(s) (srandom(s))
|
||||
#define AFL_R(x) (random() % (x))
|
||||
#else
|
||||
#define AFL_SR(s) ((void)s)
|
||||
#define AFL_R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#else
|
||||
#define AFL_SR(s) ((void)s)
|
||||
#define AFL_R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#else
|
||||
#if defined(__linux__)
|
||||
#define SR(s) (srandom(s))
|
||||
#define R(x) (random() % (x))
|
||||
#else
|
||||
#define SR(s) ((void)s)
|
||||
#define R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define SR(s) (srandom(s))
|
||||
#define R(x) (random() % (x))
|
||||
#else
|
||||
#define SR(s) ((void)s)
|
||||
#define R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#endif /* ^AFL_LLVM_PASS */
|
||||
|
||||
#define STRINGIFY_INTERNAL(x) #x
|
||||
@ -116,11 +156,19 @@ typedef int64_t s64;
|
||||
#define MEM_BARRIER() __asm__ volatile("" ::: "memory")
|
||||
|
||||
#if __GNUC__ < 6
|
||||
#define likely(_x) (_x)
|
||||
#define unlikely(_x) (_x)
|
||||
#ifndef likely
|
||||
#define likely(_x) (_x)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) (_x)
|
||||
#endif
|
||||
#else
|
||||
#define likely(_x) __builtin_expect(!!(_x), 1)
|
||||
#define unlikely(_x) __builtin_expect(!!(_x), 0)
|
||||
#ifndef likely
|
||||
#define likely(_x) __builtin_expect(!!(_x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) __builtin_expect(!!(_x), 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ! _HAVE_TYPES_H */
|
||||
|
@ -18,18 +18,17 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS += -I ../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
ifdef USEHUGEPAGE
|
||||
CFLAGS += -DUSEHUGEPAGE
|
||||
endif
|
||||
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
|
||||
all: libdislocator.so
|
||||
|
||||
VPATH = ..
|
||||
libdislocator.so: libdislocator.so.c ../config.h
|
||||
$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -shared -fPIC libdislocator.so.c -o ../$@ $(LDFLAGS)
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
@ -40,5 +39,5 @@ clean:
|
||||
install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../libdislocator.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 README.dislocator.md $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
|
||||
|
||||
|
@ -30,39 +30,39 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/vm_statistics.h>
|
||||
#include <mach/vm_statistics.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/param.h>
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#ifdef __NR_getrandom
|
||||
#define arc4random_buf(p, l) \
|
||||
do { \
|
||||
\
|
||||
ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
|
||||
if (rd != l) DEBUGF("getrandom failed"); \
|
||||
\
|
||||
} while (0)
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#ifdef __NR_getrandom
|
||||
#define arc4random_buf(p, l) \
|
||||
do { \
|
||||
\
|
||||
ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
|
||||
if (rd != l) DEBUGF("getrandom failed"); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#include <time.h>
|
||||
#define arc4random_buf(p, l) \
|
||||
do { \
|
||||
\
|
||||
srand(time(NULL)); \
|
||||
u32 i; \
|
||||
u8* ptr = (u8*)p; \
|
||||
for (i = 0; i < l; i++) \
|
||||
ptr[i] = rand() % INT_MAX; \
|
||||
\
|
||||
} while (0)
|
||||
#else
|
||||
#include <time.h>
|
||||
#define arc4random_buf(p, l) \
|
||||
do { \
|
||||
\
|
||||
srand(time(NULL)); \
|
||||
u32 i; \
|
||||
u8 *ptr = (u8 *)p; \
|
||||
for (i = 0; i < l; i++) \
|
||||
ptr[i] = rand() % INT_MAX; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
@ -83,11 +83,11 @@ typedef struct {
|
||||
#define ALLOC_ALIGN_SIZE (_Alignof(max_align_t))
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_SIZE 4096
|
||||
#endif /* !PAGE_SIZE */
|
||||
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif /* !MAP_ANONYMOUS */
|
||||
|
||||
#define SUPER_PAGE_SIZE 1 << 21
|
||||
@ -136,8 +136,8 @@ typedef struct {
|
||||
|
||||
#define TAIL_ALLOC_CANARY 0xAC
|
||||
|
||||
#define PTR_C(_p) (((u32*)(_p))[-1])
|
||||
#define PTR_L(_p) (((u32*)(_p))[-2])
|
||||
#define PTR_C(_p) (((u32 *)(_p))[-1])
|
||||
#define PTR_L(_p) (((u32 *)(_p))[-2])
|
||||
|
||||
/* Configurable stuff (use AFL_LD_* to set): */
|
||||
|
||||
@ -148,8 +148,8 @@ static u8 alloc_verbose, /* Additional debug messages */
|
||||
align_allocations; /* Force alignment to sizeof(void*) */
|
||||
|
||||
#if defined __OpenBSD__ || defined __APPLE__
|
||||
#define __thread
|
||||
#warning no thread support available
|
||||
#define __thread
|
||||
#warning no thread support available
|
||||
#endif
|
||||
static __thread size_t total_mem; /* Currently allocated mem */
|
||||
|
||||
@ -161,9 +161,9 @@ static u32 alloc_canary;
|
||||
so that it is right-aligned to that boundary. Since it always uses mmap(),
|
||||
the returned memory will be zeroed. */
|
||||
|
||||
static void* __dislocator_alloc(size_t len) {
|
||||
static void *__dislocator_alloc(size_t len) {
|
||||
|
||||
u8* ret;
|
||||
u8 * ret;
|
||||
size_t tlen;
|
||||
int flags, fd, sp;
|
||||
|
||||
@ -183,39 +183,39 @@ static void* __dislocator_alloc(size_t len) {
|
||||
else
|
||||
rlen = len;
|
||||
|
||||
/* We will also store buffer length and a canary below the actual buffer, so
|
||||
let's add 8 bytes for that. */
|
||||
|
||||
tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
fd = -1;
|
||||
#if defined(USEHUGEPAGE)
|
||||
sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
if (sp) fd = VM_FLAGS_SUPERPAGE_SIZE_2MB;
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__)
|
||||
if (sp) flags |= MAP_HUGETLB;
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__)
|
||||
if (sp) flags |= MAP_ALIGNED_SUPER;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
(void)sp;
|
||||
#endif
|
||||
|
||||
/* We will also store buffer length and a canary below the actual buffer, so
|
||||
let's add 8 bytes for that. */
|
||||
|
||||
ret = (u8*)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
#if defined(USEHUGEPAGE)
|
||||
/* We try one more time with regular call */
|
||||
if (ret == MAP_FAILED) {
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
fd = -1;
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__)
|
||||
flags &= -MAP_HUGETLB;
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__)
|
||||
flags &= -MAP_ALIGNED_SUPER;
|
||||
#endif
|
||||
ret = (u8*)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
#endif
|
||||
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
|
||||
}
|
||||
|
||||
@ -265,9 +265,9 @@ static void* __dislocator_alloc(size_t len) {
|
||||
/* The "user-facing" wrapper for calloc(). This just checks for overflows and
|
||||
displays debug messages if requested. */
|
||||
|
||||
void* calloc(size_t elem_len, size_t elem_cnt) {
|
||||
void *calloc(size_t elem_len, size_t elem_cnt) {
|
||||
|
||||
void* ret;
|
||||
void *ret;
|
||||
|
||||
size_t len = elem_len * elem_cnt;
|
||||
|
||||
@ -296,17 +296,13 @@ void* calloc(size_t elem_len, size_t elem_cnt) {
|
||||
|
||||
}
|
||||
|
||||
/* TODO: add a wrapper for posix_memalign, otherwise apps who use it,
|
||||
will fail when freeing the memory.
|
||||
*/
|
||||
|
||||
/* The wrapper for malloc(). Roughly the same, also clobbers the returned
|
||||
memory (unlike calloc(), malloc() is not guaranteed to return zeroed
|
||||
memory). */
|
||||
|
||||
void* malloc(size_t len) {
|
||||
void *malloc(size_t len) {
|
||||
|
||||
void* ret;
|
||||
void *ret;
|
||||
|
||||
ret = __dislocator_alloc(len);
|
||||
|
||||
@ -322,7 +318,7 @@ void* malloc(size_t len) {
|
||||
If the region is already freed, the code will segfault during the attempt to
|
||||
read the canary. Not very graceful, but works, right? */
|
||||
|
||||
void free(void* ptr) {
|
||||
void free(void *ptr) {
|
||||
|
||||
u32 len;
|
||||
|
||||
@ -338,7 +334,7 @@ void free(void* ptr) {
|
||||
|
||||
if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1))) {
|
||||
|
||||
u8* ptr_ = ptr;
|
||||
u8 * ptr_ = ptr;
|
||||
size_t rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
|
||||
for (; len < rlen; ++len)
|
||||
if (ptr_[len] != TAIL_ALLOC_CANARY)
|
||||
@ -361,9 +357,9 @@ void free(void* ptr) {
|
||||
/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer,
|
||||
move data, and then free (aka mprotect()) the original one. */
|
||||
|
||||
void* realloc(void* ptr, size_t len) {
|
||||
void *realloc(void *ptr, size_t len) {
|
||||
|
||||
void* ret;
|
||||
void *ret;
|
||||
|
||||
ret = malloc(len);
|
||||
|
||||
@ -387,10 +383,10 @@ void* realloc(void* ptr, size_t len) {
|
||||
if the requested size fits within the alignment we do
|
||||
a normal request */
|
||||
|
||||
int posix_memalign(void** ptr, size_t align, size_t len) {
|
||||
int posix_memalign(void **ptr, size_t align, size_t len) {
|
||||
|
||||
// if (*ptr == NULL) return EINVAL; // (andrea) Why? I comment it out for now
|
||||
if ((align % 2) || (align % sizeof(void*))) return EINVAL;
|
||||
if ((align % 2) || (align % sizeof(void *))) return EINVAL;
|
||||
if (len == 0) {
|
||||
|
||||
*ptr = NULL;
|
||||
@ -413,9 +409,9 @@ int posix_memalign(void** ptr, size_t align, size_t len) {
|
||||
|
||||
/* just the non-posix fashion */
|
||||
|
||||
void* memalign(size_t align, size_t len) {
|
||||
void *memalign(size_t align, size_t len) {
|
||||
|
||||
void* ret = NULL;
|
||||
void *ret = NULL;
|
||||
|
||||
if (posix_memalign(&ret, align, len)) {
|
||||
|
||||
@ -429,9 +425,9 @@ void* memalign(size_t align, size_t len) {
|
||||
|
||||
/* sort of C11 alias of memalign only more severe, alignment-wise */
|
||||
|
||||
void* aligned_alloc(size_t align, size_t len) {
|
||||
void *aligned_alloc(size_t align, size_t len) {
|
||||
|
||||
void* ret = NULL;
|
||||
void *ret = NULL;
|
||||
|
||||
if ((len % align)) return NULL;
|
||||
|
||||
@ -447,11 +443,11 @@ void* aligned_alloc(size_t align, size_t len) {
|
||||
|
||||
/* specific BSD api mainly checking possible overflow for the size */
|
||||
|
||||
void* reallocarray(void* ptr, size_t elem_len, size_t elem_cnt) {
|
||||
void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
|
||||
|
||||
const size_t elem_lim = 1UL << (sizeof(size_t) * 4);
|
||||
const size_t elem_tot = elem_len * elem_cnt;
|
||||
void* ret = NULL;
|
||||
void * ret = NULL;
|
||||
|
||||
if ((elem_len >= elem_lim || elem_cnt >= elem_lim) && elem_len > 0 &&
|
||||
elem_cnt > (SIZE_MAX / elem_len)) {
|
||||
@ -468,21 +464,33 @@ void* reallocarray(void* ptr, size_t elem_len, size_t elem_cnt) {
|
||||
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
size_t malloc_usable_size(void *ptr) {
|
||||
|
||||
#else
|
||||
size_t malloc_usable_size(const void *ptr) {
|
||||
|
||||
#endif
|
||||
|
||||
return ptr ? PTR_L(ptr) : 0;
|
||||
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void __dislocator_init(void) {
|
||||
|
||||
u8* tmp = (u8*)getenv("AFL_LD_LIMIT_MB");
|
||||
u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
u8* tok;
|
||||
s32 mmem = (s32)strtol((char*)tmp, (char**)&tok, 10);
|
||||
u8 *tok;
|
||||
s32 mmem = (s32)strtol((char *)tmp, (char **)&tok, 10);
|
||||
if (*tok != '\0' || errno == ERANGE) FATAL("Bad value for AFL_LD_LIMIT_MB");
|
||||
max_mem = mmem * 1024 * 1024;
|
||||
|
||||
}
|
||||
|
||||
alloc_canary = ALLOC_CANARY;
|
||||
tmp = (u8*)getenv("AFL_RANDOM_ALLOC_CANARY");
|
||||
tmp = (u8 *)getenv("AFL_RANDOM_ALLOC_CANARY");
|
||||
|
||||
if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary));
|
||||
|
||||
|
@ -15,33 +15,56 @@
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS += -I ../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
ifeq "$(shell uname)" "Linux"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
ifeq "$(shell uname)" "FreeBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "NetBSD"
|
||||
TARGETS = libtokencap.so
|
||||
endif
|
||||
ifeq "$(shell uname)" "DragonFly"
|
||||
TARGETS = libtokencap.so
|
||||
LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
UNAME_S =$(shell uname -s)# GNU make
|
||||
UNAME_S:sh=uname -s # BSD make
|
||||
_UNIQ=_QINU_
|
||||
|
||||
_OS_DL = $(_UNIQ)$(UNAME_S)
|
||||
__OS_DL = $(_OS_DL:$(_UNIQ)Linux=$(_UNIQ))
|
||||
___OS_DL = $(__OS_DL:$(_UNIQ)Darwin=$(_UNIQ))
|
||||
____OS_DL = $(___OS_DL:$(_UNIQ)DragonFly=$(_UNIQ))
|
||||
_____OS_DL = $(____OS_DL:$(_UNIQ)$(UNAME_S)=)
|
||||
______OS_DL = $(_____OS_DL:$(_UNIQ)="-ldl")
|
||||
|
||||
_OS_TARGET = $(____OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
|
||||
__OS_TARGET = $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
|
||||
___OS_TARGET = $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
|
||||
____OS_TARGET = $(___OS_TARGET:$(_UNIQ)$(UNAME_S)=)
|
||||
|
||||
TARGETS = $(____OS_TARGET:$(_UNIQ)=libtokencap.so)
|
||||
|
||||
LDFLAGS += $(______OS_DL)
|
||||
|
||||
#ifeq "$(shell uname)" "Linux"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "Darwin"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "FreeBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "OpenBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "NetBSD"
|
||||
# TARGETS = libtokencap.so
|
||||
#endif
|
||||
#ifeq "$(shell uname)" "DragonFly"
|
||||
# TARGETS = libtokencap.so
|
||||
# LDFLAGS += -ldl
|
||||
#endif
|
||||
all: $(TARGETS)
|
||||
|
||||
VPATH = ..
|
||||
@ -50,6 +73,16 @@ libtokencap.so: libtokencap.so.c ../config.h
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
debug:
|
||||
@echo $(UNAME_S)$(_UNIQ) | hexdump -C
|
||||
@echo from $(____OS_DL) : $(_UNIQ)$(UNAME_S) = -\> $(_____OS_DL)
|
||||
@echo from $(_____OS_DL) : $(_UNIQ) = -ldl -\> $(______OS_DL)
|
||||
@echo from $(____OS_DL) : $(_UNIQ)FreeBSD = $(_UNIQ) -\> $(_OS_TARGET)
|
||||
@echo from $(_OS_TARGET) : $(_UNIQ)OpenBSD = $(_UNIQ) -\> $(__OS_TARGET)
|
||||
@echo from $(__OS_TARGET) : $(_UNIQ)NetBSD = $(_UNIQ) -\> $(___OS_TARGET)
|
||||
@echo from $(___OS_TARGET) : $(_UNIQ)$(_UNIQ) = -\> $(____OS_TARGET)
|
||||
@echo from $(____OS_TARGET) : $(_UNIQ) = libtokencap.so -\> $(TARGETS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
|
||||
rm -f ../libtokencap.so
|
||||
@ -57,5 +90,4 @@ clean:
|
||||
install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 README.tokencap.md $${DESTDIR}$(HELPER_PATH)
|
||||
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
|
||||
|
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -35,18 +35,20 @@
|
||||
|
||||
#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && \
|
||||
!defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__
|
||||
#error "Sorry, this library is unsupported in this platform for now!"
|
||||
#error "Sorry, this library is unsupported in this platform for now!"
|
||||
#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
|
||||
!__NetBSD__*/
|
||||
|
||||
#if defined __APPLE__
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach_init.h>
|
||||
#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#if !defined __NetBSD__
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
@ -54,16 +56,16 @@
|
||||
#ifdef RTLD_NEXT
|
||||
/* The libc functions are a magnitude faster than our replacements.
|
||||
Use them when RTLD_NEXT is available. */
|
||||
int (*__libc_strcmp)(const char* str1, const char* str2);
|
||||
int (*__libc_strncmp)(const char* str1, const char* str2, size_t len);
|
||||
int (*__libc_strcasecmp)(const char* str1, const char* str2);
|
||||
int (*__libc_strncasecmp)(const char* str1, const char* str2, size_t len);
|
||||
int (*__libc_memcmp)(const void* mem1, const void* mem2, size_t len);
|
||||
int (*__libc_bcmp)(const void* mem1, const void* mem2, size_t len);
|
||||
char* (*__libc_strstr)(const char* haystack, const char* needle);
|
||||
char* (*__libc_strcasestr)(const char* haystack, const char* needle);
|
||||
void* (*__libc_memmem)(const void* haystack, size_t haystack_len,
|
||||
const void* needle, size_t needle_len);
|
||||
int (*__libc_strcmp)(const char *str1, const char *str2);
|
||||
int (*__libc_strncmp)(const char *str1, const char *str2, size_t len);
|
||||
int (*__libc_strcasecmp)(const char *str1, const char *str2);
|
||||
int (*__libc_strncasecmp)(const char *str1, const char *str2, size_t len);
|
||||
int (*__libc_memcmp)(const void *mem1, const void *mem2, size_t len);
|
||||
int (*__libc_bcmp)(const void *mem1, const void *mem2, size_t len);
|
||||
char *(*__libc_strstr)(const char *haystack, const char *needle);
|
||||
char *(*__libc_strcasestr)(const char *haystack, const char *needle);
|
||||
void *(*__libc_memmem)(const void *haystack, size_t haystack_len,
|
||||
const void *needle, size_t needle_len);
|
||||
#endif
|
||||
|
||||
/* Mapping data and such */
|
||||
@ -86,7 +88,7 @@ static void __tokencap_load_mappings(void) {
|
||||
#if defined __linux__
|
||||
|
||||
u8 buf[MAX_LINE];
|
||||
FILE* f = fopen("/proc/self/maps", "r");
|
||||
FILE *f = fopen("/proc/self/maps", "r");
|
||||
|
||||
__tokencap_ro_loaded = 1;
|
||||
|
||||
@ -100,8 +102,8 @@ static void __tokencap_load_mappings(void) {
|
||||
if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue;
|
||||
if (wf == 'w' || rf != 'r') continue;
|
||||
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void*)st;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void*)en;
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void *)st;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void *)en;
|
||||
|
||||
if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
|
||||
|
||||
@ -136,8 +138,8 @@ static void __tokencap_load_mappings(void) {
|
||||
if ((region.protection & VM_PROT_READ) &&
|
||||
!(region.protection & VM_PROT_WRITE)) {
|
||||
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void*)base;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void*)(base + size);
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void *)base;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void *)(base + size);
|
||||
|
||||
if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
|
||||
|
||||
@ -152,25 +154,25 @@ static void __tokencap_load_mappings(void) {
|
||||
|
||||
#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
|
||||
|
||||
#if defined __FreeBSD__
|
||||
#if defined __FreeBSD__
|
||||
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid};
|
||||
#elif defined __OpenBSD__
|
||||
#elif defined __OpenBSD__
|
||||
int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid};
|
||||
#elif defined __NetBSD__
|
||||
#elif defined __NetBSD__
|
||||
int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid,
|
||||
sizeof(struct kinfo_vmentry)};
|
||||
#endif
|
||||
#endif
|
||||
char * buf, *low, *high;
|
||||
size_t miblen = sizeof(mib) / sizeof(mib[0]);
|
||||
size_t len;
|
||||
|
||||
if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return;
|
||||
|
||||
#if defined __FreeBSD__ || defined __NetBSD__
|
||||
#if defined __FreeBSD__ || defined __NetBSD__
|
||||
len = len * 4 / 3;
|
||||
#elif defined __OpenBSD__
|
||||
#elif defined __OpenBSD__
|
||||
len -= len % sizeof(struct kinfo_vmentry);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (buf == MAP_FAILED) return;
|
||||
@ -189,24 +191,24 @@ static void __tokencap_load_mappings(void) {
|
||||
|
||||
while (low < high) {
|
||||
|
||||
struct kinfo_vmentry* region = (struct kinfo_vmentry*)low;
|
||||
struct kinfo_vmentry *region = (struct kinfo_vmentry *)low;
|
||||
|
||||
#if defined __FreeBSD__ || defined __NetBSD__
|
||||
#if defined __FreeBSD__ || defined __NetBSD__
|
||||
|
||||
#if defined __FreeBSD__
|
||||
#if defined __FreeBSD__
|
||||
size_t size = region->kve_structsize;
|
||||
|
||||
if (size == 0) break;
|
||||
#elif defined __NetBSD__
|
||||
#elif defined __NetBSD__
|
||||
size_t size = sizeof(*region);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* We go through the whole mapping of the process and track read-only
|
||||
* addresses */
|
||||
if ((region->kve_protection & KVME_PROT_READ) &&
|
||||
!(region->kve_protection & KVME_PROT_WRITE)) {
|
||||
|
||||
#elif defined __OpenBSD__
|
||||
#elif defined __OpenBSD__
|
||||
|
||||
size_t size = sizeof(*region);
|
||||
|
||||
@ -215,9 +217,9 @@ static void __tokencap_load_mappings(void) {
|
||||
if ((region->kve_protection & KVE_PROT_READ) &&
|
||||
!(region->kve_protection & KVE_PROT_WRITE)) {
|
||||
|
||||
#endif
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void*)region->kve_start;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void*)region->kve_end;
|
||||
#endif
|
||||
__tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start;
|
||||
__tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end;
|
||||
|
||||
if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
|
||||
|
||||
@ -234,7 +236,7 @@ static void __tokencap_load_mappings(void) {
|
||||
|
||||
/* Check an address against the list of read-only mappings. */
|
||||
|
||||
static u8 __tokencap_is_ro(const void* ptr) {
|
||||
static u8 __tokencap_is_ro(const void *ptr) {
|
||||
|
||||
u32 i;
|
||||
|
||||
@ -250,7 +252,7 @@ static u8 __tokencap_is_ro(const void* ptr) {
|
||||
/* Dump an interesting token to output file, quoting and escaping it
|
||||
properly. */
|
||||
|
||||
static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
|
||||
static void __tokencap_dump(const u8 *ptr, size_t len, u8 is_text) {
|
||||
|
||||
u8 buf[MAX_AUTO_EXTRA * 4 + 1];
|
||||
u32 i;
|
||||
@ -274,7 +276,8 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
|
||||
pos += 4;
|
||||
break;
|
||||
|
||||
default: buf[pos++] = ptr[i];
|
||||
default:
|
||||
buf[pos++] = ptr[i];
|
||||
|
||||
}
|
||||
|
||||
@ -293,7 +296,7 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
|
||||
|
||||
#undef strcmp
|
||||
|
||||
int strcmp(const char* str1, const char* str2) {
|
||||
int strcmp(const char *str1, const char *str2) {
|
||||
|
||||
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
|
||||
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
|
||||
@ -317,7 +320,7 @@ int strcmp(const char* str1, const char* str2) {
|
||||
|
||||
#undef strncmp
|
||||
|
||||
int strncmp(const char* str1, const char* str2, size_t len) {
|
||||
int strncmp(const char *str1, const char *str2, size_t len) {
|
||||
|
||||
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
|
||||
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
|
||||
@ -343,7 +346,7 @@ int strncmp(const char* str1, const char* str2, size_t len) {
|
||||
|
||||
#undef strcasecmp
|
||||
|
||||
int strcasecmp(const char* str1, const char* str2) {
|
||||
int strcasecmp(const char *str1, const char *str2) {
|
||||
|
||||
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
|
||||
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
|
||||
@ -367,7 +370,7 @@ int strcasecmp(const char* str1, const char* str2) {
|
||||
|
||||
#undef strncasecmp
|
||||
|
||||
int strncasecmp(const char* str1, const char* str2, size_t len) {
|
||||
int strncasecmp(const char *str1, const char *str2, size_t len) {
|
||||
|
||||
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
|
||||
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
|
||||
@ -393,7 +396,7 @@ int strncasecmp(const char* str1, const char* str2, size_t len) {
|
||||
|
||||
#undef memcmp
|
||||
|
||||
int memcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
int memcmp(const void *mem1, const void *mem2, size_t len) {
|
||||
|
||||
if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
|
||||
if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
|
||||
@ -402,8 +405,8 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
if (__libc_memcmp) return __libc_memcmp(mem1, mem2, len);
|
||||
#endif
|
||||
|
||||
const char* strmem1 = (const char*)mem1;
|
||||
const char* strmem2 = (const char*)mem2;
|
||||
const char *strmem1 = (const char *)mem1;
|
||||
const char *strmem2 = (const char *)mem2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
@ -420,7 +423,7 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
|
||||
#undef bcmp
|
||||
|
||||
int bcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
int bcmp(const void *mem1, const void *mem2, size_t len) {
|
||||
|
||||
if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
|
||||
if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
|
||||
@ -429,8 +432,8 @@ int bcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
if (__libc_bcmp) return __libc_bcmp(mem1, mem2, len);
|
||||
#endif
|
||||
|
||||
const char* strmem1 = (const char*)mem1;
|
||||
const char* strmem2 = (const char*)mem2;
|
||||
const char *strmem1 = (const char *)mem1;
|
||||
const char *strmem2 = (const char *)mem2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
@ -447,7 +450,7 @@ int bcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
|
||||
#undef strstr
|
||||
|
||||
char* strstr(const char* haystack, const char* needle) {
|
||||
char *strstr(const char *haystack, const char *needle) {
|
||||
|
||||
if (__tokencap_is_ro(haystack))
|
||||
__tokencap_dump(haystack, strlen(haystack), 1);
|
||||
@ -460,13 +463,13 @@ char* strstr(const char* haystack, const char* needle) {
|
||||
|
||||
do {
|
||||
|
||||
const char* n = needle;
|
||||
const char* h = haystack;
|
||||
const char *n = needle;
|
||||
const char *h = haystack;
|
||||
|
||||
while (*n && *h && *n == *h)
|
||||
n++, h++;
|
||||
|
||||
if (!*n) return (char*)haystack;
|
||||
if (!*n) return (char *)haystack;
|
||||
|
||||
} while (*(haystack++));
|
||||
|
||||
@ -476,7 +479,7 @@ char* strstr(const char* haystack, const char* needle) {
|
||||
|
||||
#undef strcasestr
|
||||
|
||||
char* strcasestr(const char* haystack, const char* needle) {
|
||||
char *strcasestr(const char *haystack, const char *needle) {
|
||||
|
||||
if (__tokencap_is_ro(haystack))
|
||||
__tokencap_dump(haystack, strlen(haystack), 1);
|
||||
@ -489,13 +492,13 @@ char* strcasestr(const char* haystack, const char* needle) {
|
||||
|
||||
do {
|
||||
|
||||
const char* n = needle;
|
||||
const char* h = haystack;
|
||||
const char *n = needle;
|
||||
const char *h = haystack;
|
||||
|
||||
while (*n && *h && tolower(*n) == tolower(*h))
|
||||
n++, h++;
|
||||
|
||||
if (!*n) return (char*)haystack;
|
||||
if (!*n) return (char *)haystack;
|
||||
|
||||
} while (*(haystack++));
|
||||
|
||||
@ -505,7 +508,7 @@ char* strcasestr(const char* haystack, const char* needle) {
|
||||
|
||||
#undef memmem
|
||||
|
||||
void* memmem(const void* haystack, size_t haystack_len, const void* needle,
|
||||
void *memmem(const void *haystack, size_t haystack_len, const void *needle,
|
||||
size_t needle_len) {
|
||||
|
||||
if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, haystack_len, 1);
|
||||
@ -517,19 +520,19 @@ void* memmem(const void* haystack, size_t haystack_len, const void* needle,
|
||||
return __libc_memmem(haystack, haystack_len, needle, needle_len);
|
||||
#endif
|
||||
|
||||
const char* n = (const char*)needle;
|
||||
const char* h = (const char*)haystack;
|
||||
const char *n = (const char *)needle;
|
||||
const char *h = (const char *)haystack;
|
||||
if (haystack_len < needle_len) return 0;
|
||||
if (needle_len == 0) return (void*)haystack;
|
||||
if (needle_len == 0) return (void *)haystack;
|
||||
if (needle_len == 1) return memchr(haystack, *n, haystack_len);
|
||||
|
||||
const char* end = h + (haystack_len - needle_len);
|
||||
const char *end = h + (haystack_len - needle_len);
|
||||
|
||||
do {
|
||||
|
||||
if (*h == *n) {
|
||||
|
||||
if (memcmp(h, n, needle_len) == 0) return (void*)h;
|
||||
if (memcmp(h, n, needle_len) == 0) return (void *)h;
|
||||
|
||||
}
|
||||
|
||||
@ -544,31 +547,31 @@ void* memmem(const void* haystack, size_t haystack_len, const void* needle,
|
||||
/*
|
||||
* Apache's httpd wrappers
|
||||
*/
|
||||
int ap_cstr_casecmp(const char* s1, const char* s2) {
|
||||
int ap_cstr_casecmp(const char *s1, const char *s2) {
|
||||
|
||||
return strcasecmp(s1, s2);
|
||||
|
||||
}
|
||||
|
||||
int ap_cstr_casecmpn(const char* s1, const char* s2, size_t n) {
|
||||
int ap_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
return strncasecmp(s1, s2, n);
|
||||
|
||||
}
|
||||
|
||||
const char* ap_strcasestr(const char* s1, const char* s2) {
|
||||
const char *ap_strcasestr(const char *s1, const char *s2) {
|
||||
|
||||
return strcasestr(s1, s2);
|
||||
|
||||
}
|
||||
|
||||
int apr_cstr_casecmp(const char* s1, const char* s2) {
|
||||
int apr_cstr_casecmp(const char *s1, const char *s2) {
|
||||
|
||||
return strcasecmp(s1, s2);
|
||||
|
||||
}
|
||||
|
||||
int apr_cstr_casecmpn(const char* s1, const char* s2, size_t n) {
|
||||
int apr_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
|
||||
|
||||
return strncasecmp(s1, s2, n);
|
||||
|
||||
@ -577,31 +580,31 @@ int apr_cstr_casecmpn(const char* s1, const char* s2, size_t n) {
|
||||
/*
|
||||
* *SSL wrappers
|
||||
*/
|
||||
int CRYPTO_memcmp(const void* m1, const void* m2, size_t len) {
|
||||
int CRYPTO_memcmp(const void *m1, const void *m2, size_t len) {
|
||||
|
||||
return memcmp(m1, m2, len);
|
||||
|
||||
}
|
||||
|
||||
int OPENSSL_memcmp(const void* m1, const void* m2, size_t len) {
|
||||
int OPENSSL_memcmp(const void *m1, const void *m2, size_t len) {
|
||||
|
||||
return memcmp(m1, m2, len);
|
||||
|
||||
}
|
||||
|
||||
int OPENSSL_strcasecmp(const char* s1, const char* s2) {
|
||||
int OPENSSL_strcasecmp(const char *s1, const char *s2) {
|
||||
|
||||
return strcasecmp(s1, s2);
|
||||
|
||||
}
|
||||
|
||||
int OPENSSL_strncasecmp(const char* s1, const char* s2, size_t len) {
|
||||
int OPENSSL_strncasecmp(const char *s1, const char *s2, size_t len) {
|
||||
|
||||
return strncasecmp(s1, s2, len);
|
||||
|
||||
}
|
||||
|
||||
int32_t memcmpct(const void* s1, const void* s2, size_t len) {
|
||||
int32_t memcmpct(const void *s1, const void *s2, size_t len) {
|
||||
|
||||
return memcmp(s1, s2, len);
|
||||
|
||||
@ -610,7 +613,7 @@ int32_t memcmpct(const void* s1, const void* s2, size_t len) {
|
||||
/*
|
||||
* libXML wrappers
|
||||
*/
|
||||
int xmlStrncmp(const char* s1, const char* s2, int len) {
|
||||
int xmlStrncmp(const char *s1, const char *s2, int len) {
|
||||
|
||||
if (len <= 0) { return 0; }
|
||||
if (s1 == s2) { return 0; }
|
||||
@ -620,7 +623,7 @@ int xmlStrncmp(const char* s1, const char* s2, int len) {
|
||||
|
||||
}
|
||||
|
||||
int xmlStrcmp(const char* s1, const char* s2) {
|
||||
int xmlStrcmp(const char *s1, const char *s2) {
|
||||
|
||||
if (s1 == s2) { return 0; }
|
||||
if (s1 == NULL) { return -1; }
|
||||
@ -629,7 +632,7 @@ int xmlStrcmp(const char* s1, const char* s2) {
|
||||
|
||||
}
|
||||
|
||||
int xmlStrEqual(const char* s1, const char* s2) {
|
||||
int xmlStrEqual(const char *s1, const char *s2) {
|
||||
|
||||
if (s1 == s2) { return 1; }
|
||||
if (s1 == NULL) { return 0; }
|
||||
@ -639,7 +642,7 @@ int xmlStrEqual(const char* s1, const char* s2) {
|
||||
|
||||
}
|
||||
|
||||
int xmlStrcasecmp(const char* s1, const char* s2) {
|
||||
int xmlStrcasecmp(const char *s1, const char *s2) {
|
||||
|
||||
if (s1 == s2) { return 0; }
|
||||
if (s1 == NULL) { return -1; }
|
||||
@ -648,7 +651,7 @@ int xmlStrcasecmp(const char* s1, const char* s2) {
|
||||
|
||||
}
|
||||
|
||||
int xmlStrncasecmp(const char* s1, const char* s2, int len) {
|
||||
int xmlStrncasecmp(const char *s1, const char *s2, int len) {
|
||||
|
||||
if (len <= 0) { return 0; }
|
||||
if (s1 == s2) { return 0; }
|
||||
@ -658,7 +661,7 @@ int xmlStrncasecmp(const char* s1, const char* s2, int len) {
|
||||
|
||||
}
|
||||
|
||||
const char* xmlStrstr(const char* haystack, const char* needle) {
|
||||
const char *xmlStrstr(const char *haystack, const char *needle) {
|
||||
|
||||
if (haystack == NULL) { return NULL; }
|
||||
if (needle == NULL) { return NULL; }
|
||||
@ -666,7 +669,7 @@ const char* xmlStrstr(const char* haystack, const char* needle) {
|
||||
|
||||
}
|
||||
|
||||
const char* xmlStrcasestr(const char* haystack, const char* needle) {
|
||||
const char *xmlStrcasestr(const char *haystack, const char *needle) {
|
||||
|
||||
if (haystack == NULL) { return NULL; }
|
||||
if (needle == NULL) { return NULL; }
|
||||
@ -677,13 +680,13 @@ const char* xmlStrcasestr(const char* haystack, const char* needle) {
|
||||
/*
|
||||
* Samba wrappers
|
||||
*/
|
||||
int memcmp_const_time(const void* s1, const void* s2, size_t n) {
|
||||
int memcmp_const_time(const void *s1, const void *s2, size_t n) {
|
||||
|
||||
return memcmp(s1, s2, n);
|
||||
|
||||
}
|
||||
|
||||
bool strcsequal(const void* s1, const void* s2) {
|
||||
bool strcsequal(const void *s1, const void *s2) {
|
||||
|
||||
if (s1 == s2) { return true; }
|
||||
if (!s1 || !s2) { return false; }
|
||||
@ -693,13 +696,13 @@ bool strcsequal(const void* s1, const void* s2) {
|
||||
|
||||
/* bcmp/memcmp BSD flavors, similar to CRYPTO_memcmp */
|
||||
|
||||
int timingsafe_bcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
int timingsafe_bcmp(const void *mem1, const void *mem2, size_t len) {
|
||||
|
||||
return bcmp(mem1, mem2, len);
|
||||
|
||||
}
|
||||
|
||||
int timingsafe_memcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
int timingsafe_memcmp(const void *mem1, const void *mem2, size_t len) {
|
||||
|
||||
return memcmp(mem1, mem2, len);
|
||||
|
||||
@ -709,7 +712,7 @@ int timingsafe_memcmp(const void* mem1, const void* mem2, size_t len) {
|
||||
|
||||
__attribute__((constructor)) void __tokencap_init(void) {
|
||||
|
||||
u8* fn = getenv("AFL_TOKEN_FILE");
|
||||
u8 *fn = getenv("AFL_TOKEN_FILE");
|
||||
if (fn) __tokencap_out_file = open(fn, O_RDWR | O_CREAT | O_APPEND, 0655);
|
||||
if (__tokencap_out_file == -1) __tokencap_out_file = STDERR_FILENO;
|
||||
__tokencap_pid = getpid();
|
||||
|
425
llvm_mode/GNUmakefile
Normal file
425
llvm_mode/GNUmakefile
Normal file
@ -0,0 +1,425 @@
|
||||
# american fuzzy lop++ - LLVM instrumentation
|
||||
# -----------------------------------------
|
||||
#
|
||||
# Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# LLVM integration design comes from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH ?= $(PREFIX)/lib/afl
|
||||
BIN_PATH ?= $(PREFIX)/bin
|
||||
DOC_PATH ?= $(PREFIX)/share/doc/afl
|
||||
MISC_PATH ?= $(PREFIX)/share/afl
|
||||
MAN_PATH ?= $(PREFIX)/man/man8
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
ifeq "$(HAS_OPT)" "1"
|
||||
$(error llvm_mode needs a complete llvm installation (versions 3.8.0 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
|
||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||
LLVM_STDCXX = gnu++11
|
||||
LLVM_APPLE_XCODE = $(shell clang -v 2>&1 | grep -q Apple && echo 1 || echo 0)
|
||||
LLVM_LTO = 0
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning [!] llvm_mode needs llvm-config, which was not found)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.8.0 up to 11)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
LLVM_STDCXX = c++14
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "11"
|
||||
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
|
||||
LLVM_LTO = 1
|
||||
TEST_MMAP = 1
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_LTO)" "0"
|
||||
$(info [+] llvm_mode detected llvm < 11, afl-clang-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 "CC=gcc make"
|
||||
ifeq "$(shell command -v $(CXX) 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
|
||||
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
|
||||
|
||||
# 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
|
||||
$(warn ld.lld not found, can not enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
AFL_CLANG_FUSELD=
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
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
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CFLAGS += -Wall \
|
||||
-g -Wno-pointer-sign -I ../include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
|
||||
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
|
||||
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
|
||||
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
|
||||
ifdef AFL_TRACE_PC
|
||||
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CXXFLAGS += -Wall -g -I ../include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros
|
||||
|
||||
CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fpic $(CXXFLAGS)
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
else
|
||||
CLANG_CFL += -Wl,-znodelete
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = no_build
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done
|
||||
endif
|
||||
|
||||
LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
test_deps:
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE_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-3.5 or something like that.)"; exit 1 )
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
|
||||
else
|
||||
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
|
||||
endif
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
|
||||
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -Dxxx
|
||||
ln -sf afl-clang-fast ../afl-clang-fast++
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ln -sf afl-clang-fast ../afl-clang-lto
|
||||
ln -sf afl-clang-fast ../afl-clang-lto++
|
||||
endif
|
||||
endif
|
||||
|
||||
afl-llvm-common.o: afl-llvm-common.cc afl-llvm-common.h
|
||||
$(CXX) $(CFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
|
||||
|
||||
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc afl-llvm-common.o | test_deps
|
||||
-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
|
||||
../afl-llvm-pass.so: afl-llvm-pass.so.cc 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_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
|
||||
../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
endif
|
||||
|
||||
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
|
||||
@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
endif
|
||||
|
||||
../afl-llvm-lto-instrim.so: afl-llvm-lto-instrim.so.cc afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
endif
|
||||
|
||||
# laf
|
||||
../split-switches-pass.so: split-switches-pass.so.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
../compare-transform-pass.so: compare-transform-pass.so.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
../split-compares-pass.so: split-compares-pass.so.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
# /laf
|
||||
|
||||
../cmplog-routines-pass.so: cmplog-routines-pass.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
|
||||
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
|
||||
|
||||
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@
|
||||
|
||||
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-clang-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
install: all
|
||||
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
|
||||
if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../split-compares-pass.so ]; then set -e; install -m 755 ../split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../split-switches-pass.so ]; then set -e; install -m 755 ../split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f ../cmplog-instructions-pass.so ]; then set -e; install -m 755 ../cmplog-*-pass.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
set -e; if [ -f ../afl-clang-fast ] ; then ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
|
||||
install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/
|
||||
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-fast++.8
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-lto.8
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-lto++.8
|
||||
endif
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
|
||||
rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld ../afl-ld ../afl-llvm-rt*.o
|
@ -12,13 +12,13 @@ typedef long double max_align_t;
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#endif
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
@ -36,11 +36,13 @@ typedef long double max_align_t;
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "MarkNodes.h"
|
||||
#include "afl-llvm-common.h"
|
||||
#include "llvm-ngram-coverage.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "MarkNodes.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
|
||||
@ -53,7 +55,9 @@ namespace {
|
||||
struct InsTrim : public ModulePass {
|
||||
|
||||
protected:
|
||||
std::list<std::string> myWhitelist;
|
||||
uint32_t function_minimum_size = 1;
|
||||
uint32_t debug = 0;
|
||||
char * skip_nozero = NULL;
|
||||
|
||||
private:
|
||||
std::mt19937 generator;
|
||||
@ -67,24 +71,10 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
InsTrim() : ModulePass(ID), generator(0) {
|
||||
|
||||
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||
if (instWhiteListFilename) {
|
||||
|
||||
std::string line;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(instWhiteListFilename);
|
||||
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||
getline(fileStream, line);
|
||||
while (fileStream) {
|
||||
|
||||
myWhitelist.push_back(line);
|
||||
getline(fileStream, line);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
initWhitelist();
|
||||
|
||||
}
|
||||
|
||||
@ -105,33 +95,16 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
// ripped from aflgo
|
||||
static bool isBlacklisted(const Function *F) {
|
||||
|
||||
static const char *Blacklist[] = {
|
||||
|
||||
"asan.",
|
||||
"llvm.",
|
||||
"sancov.",
|
||||
"__ubsan_handle_",
|
||||
|
||||
};
|
||||
|
||||
for (auto const &BlacklistFunc : Blacklist) {
|
||||
|
||||
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
|
||||
char be_quiet = 0;
|
||||
|
||||
if (isatty(2) && !getenv("AFL_QUIET")) {
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");
|
||||
|
||||
@ -139,11 +112,19 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG") != NULL) debug = 1;
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
char *neverZero_counters_str;
|
||||
if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
|
||||
OKF("LLVM neverZero activated (by hexcoder)\n");
|
||||
if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n");
|
||||
#endif
|
||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
|
||||
getenv("LOOPHEAD") != NULL) {
|
||||
@ -152,161 +133,145 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
|
||||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
|
||||
function_minimum_size = 2;
|
||||
|
||||
unsigned int PrevLocSize = 0;
|
||||
char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
|
||||
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
|
||||
char *ctx_str = getenv("AFL_LLVM_CTX");
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
unsigned int ngram_size = 0;
|
||||
/* Decide previous location vector size (must be a power of two) */
|
||||
VectorType *PrevLocTy;
|
||||
|
||||
if (ngram_size_str)
|
||||
if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
|
||||
ngram_size > NGRAM_SIZE_MAX)
|
||||
FATAL(
|
||||
"Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
|
||||
"(%u))",
|
||||
NGRAM_SIZE_MAX);
|
||||
|
||||
if (ngram_size)
|
||||
PrevLocSize = ngram_size - 1;
|
||||
else
|
||||
#else
|
||||
if (ngram_size_str)
|
||||
#ifdef LLVM_VERSION_STRING
|
||||
FATAL(
|
||||
"Sorry, NGRAM branch coverage is not supported with llvm version %s!",
|
||||
LLVM_VERSION_STRING);
|
||||
#else
|
||||
#ifndef LLVM_VERSION_PATCH
|
||||
FATAL(
|
||||
"Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
|
||||
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
|
||||
#else
|
||||
FATAL(
|
||||
"Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
|
||||
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
PrevLocSize = 1;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
// IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
|
||||
IntegerType *IntLocTy =
|
||||
IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
|
||||
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
|
||||
#endif
|
||||
|
||||
/* Get globals for the SHM region and the previous location. Note that
|
||||
__afl_prev_loc is thread-local. */
|
||||
|
||||
GlobalVariable *AFLMapPtr =
|
||||
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
|
||||
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
|
||||
GlobalVariable *AFLPrevLoc;
|
||||
GlobalVariable *AFLContext;
|
||||
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
|
||||
|
||||
if (ctx_str)
|
||||
#ifdef __ANDROID__
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
|
||||
#else
|
||||
AFLContext = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx",
|
||||
0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
#ifdef __ANDROID__
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc");
|
||||
#else
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
|
||||
/* Initializer */ nullptr, "__afl_prev_loc",
|
||||
/* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
|
||||
/* AddressSpace */ 0, /* IsExternallyInitialized */ false);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
|
||||
#else
|
||||
AFLPrevLoc = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
|
||||
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* Create the vector shuffle mask for updating the previous block history.
|
||||
Note that the first element of the vector will store cur_loc, so just set
|
||||
it to undef to allow the optimizer to do its thing. */
|
||||
|
||||
SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};
|
||||
|
||||
for (unsigned I = 0; I < PrevLocSize - 1; ++I)
|
||||
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
|
||||
|
||||
for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
|
||||
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
|
||||
|
||||
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
|
||||
#endif
|
||||
|
||||
// this is our default
|
||||
MarkSetOpt = true;
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
|
||||
GlobalVariable *CovMapPtr = new GlobalVariable(
|
||||
M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage,
|
||||
nullptr, "__afl_area_ptr");
|
||||
|
||||
GlobalVariable *OldPrev = new GlobalVariable(
|
||||
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
|
||||
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||
|
||||
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
|
||||
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
|
||||
ConstantInt *One32 = ConstantInt::get(Int32Ty, 1);
|
||||
|
||||
u64 total_rs = 0;
|
||||
u64 total_hs = 0;
|
||||
|
||||
for (Function &F : M) {
|
||||
|
||||
// if it is external or only contains one basic block: skip it
|
||||
if (F.size() < 2) { continue; }
|
||||
if (debug) {
|
||||
|
||||
if (!myWhitelist.empty()) {
|
||||
uint32_t bb_cnt = 0;
|
||||
|
||||
bool instrumentBlock = false;
|
||||
DebugLoc Loc;
|
||||
StringRef instFilename;
|
||||
unsigned int instLine = 0;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
for (auto &BB : F) {
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
if (!Loc) Loc = IP->getDebugLoc();
|
||||
|
||||
}
|
||||
|
||||
if (Loc) {
|
||||
|
||||
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||
|
||||
instLine = cDILoc->getLine();
|
||||
instFilename = cDILoc->getFilename();
|
||||
|
||||
if (instFilename.str().empty()) {
|
||||
|
||||
/* If the original location is empty, try using the inlined location
|
||||
*/
|
||||
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||
if (oDILoc) {
|
||||
|
||||
instFilename = oDILoc->getFilename();
|
||||
instLine = oDILoc->getLine();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||
it != myWhitelist.end(); ++it) {
|
||||
|
||||
if (instFilename.str().length() >= it->length()) {
|
||||
|
||||
if (instFilename.str().compare(
|
||||
instFilename.str().length() - it->length(),
|
||||
it->length(), *it) == 0) {
|
||||
|
||||
instrumentBlock = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
for (auto &BB : F) {
|
||||
|
||||
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
if (Loc.isUnknown()) Loc = IP->getDebugLoc();
|
||||
|
||||
}
|
||||
|
||||
if (!Loc.isUnknown()) {
|
||||
|
||||
DILocation cDILoc(Loc.getAsMDNode(C));
|
||||
|
||||
instLine = cDILoc.getLineNumber();
|
||||
instFilename = cDILoc.getFilename();
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
if (!instFilename.str().empty()) {
|
||||
|
||||
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||
it != myWhitelist.end(); ++it) {
|
||||
|
||||
if (instFilename.str().length() >= it->length()) {
|
||||
|
||||
if (instFilename.str().compare(
|
||||
instFilename.str().length() - it->length(),
|
||||
it->length(), *it) == 0) {
|
||||
|
||||
instrumentBlock = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Either we couldn't figure out our location or the location is
|
||||
* not whitelisted, so we skip instrumentation. */
|
||||
if (!instrumentBlock) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
if (!instFilename.str().empty())
|
||||
SAYF(cYEL "[!] " cBRI
|
||||
"Not in whitelist, skipping %s line %u...\n",
|
||||
instFilename.str().c_str(), instLine);
|
||||
else
|
||||
SAYF(cYEL "[!] " cBRI
|
||||
"No filename information found, skipping it");
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
for (auto &BB : F)
|
||||
if (BB.size() > 0) ++bb_cnt;
|
||||
SAYF(cMGN "[D] " cRST "Function %s size %zu %u\n",
|
||||
F.getName().str().c_str(), F.size(), bb_cnt);
|
||||
|
||||
}
|
||||
|
||||
if (isBlacklisted(&F)) continue;
|
||||
if (!isInWhitelist(&F)) continue;
|
||||
|
||||
// if the function below our minimum size skip it (1 or 2)
|
||||
if (F.size() < function_minimum_size) { continue; }
|
||||
|
||||
std::unordered_set<BasicBlock *> MS;
|
||||
if (!MarkSetOpt) {
|
||||
@ -383,56 +348,75 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
// Bugfix #1: remove single block function instrumentation
|
||||
|
||||
for (BasicBlock &BB : F) {
|
||||
|
||||
if (MarkSetOpt && MS.find(&BB) == MS.end()) {
|
||||
if (MS.find(&BB) == MS.end()) { continue; }
|
||||
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
|
||||
|
||||
// Bugfix #2: instrument blocks that should be but InsTrim
|
||||
// doesn't due to an algorithmic bug
|
||||
int more_than_one = -1;
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size) {
|
||||
|
||||
for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); PI != E;
|
||||
++PI) {
|
||||
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
|
||||
PrevLoc->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
BasicBlock *Pred = *PI;
|
||||
int count = 0;
|
||||
Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
|
||||
PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
|
||||
Value *UpdatedPrevLoc = IRB.CreateInsertElement(
|
||||
ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()),
|
||||
(uint64_t)0);
|
||||
|
||||
if (more_than_one == -1) more_than_one = 0;
|
||||
for (succ_iterator SI = succ_begin(Pred), E = succ_end(Pred);
|
||||
SI != E; ++SI) {
|
||||
IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc)
|
||||
->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
BasicBlock *Succ = *SI;
|
||||
if (Succ != NULL) count++;
|
||||
} else
|
||||
|
||||
}
|
||||
#endif
|
||||
{
|
||||
|
||||
if (count > 1) more_than_one = 1;
|
||||
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (more_than_one != 1) continue;
|
||||
for (succ_iterator SI = succ_begin(&BB), E = succ_end(&BB); SI != E;
|
||||
++SI) {
|
||||
}
|
||||
|
||||
BasicBlock *Succ = *SI;
|
||||
if (Succ != NULL && MS.find(Succ) == MS.end()) {
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for (succ_iterator SI2 = succ_begin(Succ), E2 = succ_end(Succ);
|
||||
SI2 != E2; ++SI2) {
|
||||
int has_calls = 0;
|
||||
for (BasicBlock &BB : F) {
|
||||
|
||||
BasicBlock *Succ2 = *SI2;
|
||||
if (Succ2 != NULL) cnt++;
|
||||
auto PI = pred_begin(&BB);
|
||||
auto PE = pred_end(&BB);
|
||||
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
|
||||
Value * L = NULL;
|
||||
unsigned int cur_loc;
|
||||
|
||||
}
|
||||
// Context sensitive coverage
|
||||
if (ctx_str && &BB == &F.getEntryBlock()) {
|
||||
|
||||
if (cnt == 0) {
|
||||
PrevCtx = IRB.CreateLoad(AFLContext);
|
||||
PrevCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
// fprintf(stderr, "INSERT!\n");
|
||||
MS.insert(Succ);
|
||||
total_rs += 1;
|
||||
// does the function have calls? and is any of the calls larger than
|
||||
// one basic block?
|
||||
has_calls = 0;
|
||||
for (auto &BB : F) {
|
||||
|
||||
if (has_calls) break;
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
|
||||
Function *Callee = callInst->getCalledFunction();
|
||||
if (!Callee || Callee->size() < function_minimum_size)
|
||||
continue;
|
||||
else {
|
||||
|
||||
has_calls = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@ -442,40 +426,75 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// if yes we store a context ID for this function in the global var
|
||||
if (has_calls) {
|
||||
|
||||
}
|
||||
ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel());
|
||||
StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
|
||||
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
for (BasicBlock &BB : F) {
|
||||
}
|
||||
|
||||
} // END of ctx_str
|
||||
|
||||
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
|
||||
|
||||
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
|
||||
Value * L = NULL;
|
||||
if (PI == PE) {
|
||||
|
||||
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
|
||||
DenseMap<BasicBlock *, unsigned> PredMap;
|
||||
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
|
||||
cur_loc = genLabel();
|
||||
L = ConstantInt::get(Int32Ty, cur_loc);
|
||||
|
||||
BasicBlock *PBB = *PI;
|
||||
auto It = PredMap.insert({PBB, genLabel()});
|
||||
unsigned Label = It.first->second;
|
||||
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
|
||||
} else {
|
||||
|
||||
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
|
||||
DenseMap<BasicBlock *, unsigned> PredMap;
|
||||
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
|
||||
|
||||
BasicBlock *PBB = *PI;
|
||||
auto It = PredMap.insert({PBB, genLabel()});
|
||||
unsigned Label = It.first->second;
|
||||
cur_loc = Label;
|
||||
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
|
||||
|
||||
}
|
||||
|
||||
L = PN;
|
||||
|
||||
}
|
||||
|
||||
L = PN;
|
||||
|
||||
/* Load prev_loc */
|
||||
LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
|
||||
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
|
||||
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
|
||||
Value *PrevLocTrans;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
/* "For efficiency, we propose to hash the tuple as a key into the
|
||||
hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
|
||||
prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
|
||||
|
||||
if (ngram_size)
|
||||
PrevLocTrans =
|
||||
IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
|
||||
else
|
||||
#endif
|
||||
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
|
||||
|
||||
if (ctx_str)
|
||||
PrevLocTrans =
|
||||
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
|
||||
|
||||
/* Load SHM pointer */
|
||||
LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr);
|
||||
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
|
||||
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
Value *MapPtrIdx =
|
||||
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, L));
|
||||
Value *MapPtrIdx;
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ngram_size)
|
||||
MapPtrIdx = IRB.CreateGEP(
|
||||
MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty));
|
||||
else
|
||||
#endif
|
||||
MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L));
|
||||
|
||||
/* Update bitmap */
|
||||
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
|
||||
@ -488,8 +507,7 @@ struct InsTrim : public ModulePass {
|
||||
NULL) // with llvm 9 we make this the default as the bug in llvm is
|
||||
// then fixed
|
||||
#else
|
||||
if (1) // with llvm 9 we make this the default as the bug in llvm is
|
||||
// then fixed
|
||||
if (!skip_nozero)
|
||||
#endif
|
||||
{
|
||||
|
||||
@ -512,10 +530,22 @@ struct InsTrim : public ModulePass {
|
||||
IRB.CreateStore(Incr, MapPtrIdx)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
// Bugfix #3: save the actually location ID to OldPrev
|
||||
Value *Shr = IRB.CreateLShr(L, One32);
|
||||
IRB.CreateStore(Shr, OldPrev)
|
||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
if (ctx_str && has_calls) {
|
||||
|
||||
// in CTX mode we have to restore the original context for the
|
||||
// caller - she might be calling other functions which need the
|
||||
// correct CTX
|
||||
Instruction *Inst = BB.getTerminator();
|
||||
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
|
||||
|
||||
IRBuilder<> Post_IRB(Inst);
|
||||
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
|
||||
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
total_instr++;
|
||||
|
||||
@ -523,15 +553,20 @@ struct InsTrim : public ModulePass {
|
||||
|
||||
}
|
||||
|
||||
char modeline[100];
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
|
||||
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
|
||||
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
|
||||
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
if (!be_quiet) {
|
||||
|
||||
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr,
|
||||
total_rs, total_hs, modeline);
|
||||
char modeline[100];
|
||||
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
|
||||
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
|
||||
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
|
||||
getenv("AFL_USE_MSAN") ? ", MSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
|
||||
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr,
|
||||
total_rs, total_hs, modeline);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
@ -1,276 +1,2 @@
|
||||
#
|
||||
# american fuzzy lop++ - LLVM instrumentation
|
||||
# -----------------------------------------
|
||||
#
|
||||
# Written by Laszlo Szekeres <lszekeres@google.com> and
|
||||
# Michal Zalewski
|
||||
#
|
||||
# LLVM integration design comes from Laszlo Szekeres.
|
||||
#
|
||||
# Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
|
||||
# For Heiko:
|
||||
#TEST_MMAP=1
|
||||
HASH=\#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
BIN_PATH = $(PREFIX)/bin
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
|
||||
ifeq "$(HAS_OPT)" "1"
|
||||
$(error llvm_mode needs a complete llvm installation (versions 3.8.0 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
|
||||
endif
|
||||
else
|
||||
LLVM_CONFIG ?= llvm-config
|
||||
endif
|
||||
|
||||
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null )
|
||||
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-7]|^1[2-9]' && echo 1 || echo 0 )
|
||||
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
|
||||
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
|
||||
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
|
||||
LLVM_STDCXX = gnu++11
|
||||
LLVM_APPLE = $(shell clang -v 2>&1 | grep -iq apple && echo 1 || echo 0)
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning llvm_mode needs llvm-config, which was not found)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(warning llvm_mode only supports llvm versions 3.8.0 up to 11)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_MAJOR)" "9"
|
||||
$(info llvm_mode detected llvm 9, enabling neverZero implementation)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_NEW_API)" "1"
|
||||
$(info llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
|
||||
LLVM_STDCXX = c++14
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_APPLE)" "1"
|
||||
$(warning llvm_mode will not compile with Xcode clang...)
|
||||
endif
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops
|
||||
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I ../include/ \
|
||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
|
||||
-DLLVM_VERSION=\"$(LLVMVER)\"
|
||||
ifdef AFL_TRACE_PC
|
||||
CFLAGS += -DUSE_TRACE_PC=1
|
||||
endif
|
||||
|
||||
CXXFLAGS ?= -O3 -funroll-loops
|
||||
CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -I ../include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros
|
||||
|
||||
CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS)
|
||||
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
|
||||
|
||||
|
||||
# User teor2345 reports that this is required to make things work on MacOS X.
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "OpenBSD"
|
||||
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
|
||||
endif
|
||||
|
||||
# We were using llvm-config --bindir to get the location of clang, but
|
||||
# this seems to be busted on some distros, so using the one in $PATH is
|
||||
# probably better.
|
||||
|
||||
CC = $(LLVM_BINDIR)/clang
|
||||
CXX = $(LLVM_BINDIR)/clang++
|
||||
|
||||
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
|
||||
# llvm-config --bindir is not providing a valid path, so ...
|
||||
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
|
||||
# we found one in the local install directory, lets use these
|
||||
CC = $(BIN_DIR)/clang
|
||||
CXX = $(BIN_DIR)/clang++
|
||||
else
|
||||
# hope for the best
|
||||
$(warning we have trouble finding clang/clang++ - llvm-config is not helping us)
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
endif
|
||||
endif
|
||||
|
||||
# sanity check.
|
||||
# Are versions of clang --version and llvm-config --version equal?
|
||||
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
SHMAT_OK=1
|
||||
else
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifeq "$(TEST_MMAP)" "1"
|
||||
SHMAT_OK=0
|
||||
CFLAGS+=-DUSEMMAP=1
|
||||
LDFLAGS += -lrt
|
||||
endif
|
||||
|
||||
ifndef AFL_TRACE_PC
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
|
||||
else
|
||||
PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
|
||||
endif
|
||||
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
CC = $(shell $(LLVM_CONFIG) --bindir)/clang
|
||||
CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
|
||||
endif
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE)" "00"
|
||||
NO_BUILD = 1
|
||||
endif
|
||||
|
||||
ifeq "$(NO_BUILD)" "1"
|
||||
TARGETS = no_build
|
||||
else
|
||||
TARGETS = test_shm test_deps $(PROGS) afl-clang-fast.8 test_build all_done
|
||||
endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
ifeq "$(SHMAT_OK)" "1"
|
||||
|
||||
test_shm:
|
||||
@echo "[+] shmat seems to be working."
|
||||
@rm -f .test2
|
||||
|
||||
else
|
||||
|
||||
test_shm:
|
||||
@echo "[-] shmat seems not to be working, switching to mmap implementation"
|
||||
|
||||
endif
|
||||
|
||||
no_build:
|
||||
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
|
||||
|
||||
test_deps:
|
||||
ifndef AFL_TRACE_PC
|
||||
@echo "[*] Checking for working 'llvm-config'..."
|
||||
ifneq "$(LLVM_APPLE)" "1"
|
||||
@which $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
|
||||
endif
|
||||
else
|
||||
@echo "[!] Note: using -fsanitize=trace-pc mode (this will fail with older LLVM)."
|
||||
endif
|
||||
@echo "[*] Checking for working '$(CC)'..."
|
||||
@which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
|
||||
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
|
||||
ifneq "$(CLANGVER)" "$(LLVMVER)"
|
||||
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
|
||||
@echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang"
|
||||
else
|
||||
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
|
||||
endif
|
||||
@echo "[*] Checking for '../afl-showmap'..."
|
||||
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
|
||||
@echo "[+] All set and ready to build."
|
||||
|
||||
afl-common.o: ../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
|
||||
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS)
|
||||
ln -sf afl-clang-fast ../afl-clang-fast++
|
||||
|
||||
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps
|
||||
-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
# laf
|
||||
../split-switches-pass.so: split-switches-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../compare-transform-pass.so: compare-transform-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
../split-compares-pass.so: split-compares-pass.so.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
# /laf
|
||||
|
||||
../cmplog-routines-pass.so: cmplog-routines-pass.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc | test_deps
|
||||
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
|
||||
|
||||
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
|
||||
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CFLAGS) -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CFLAGS) -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
|
||||
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
|
||||
../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ../afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/vanhauser-thc/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
|
||||
@echo "[+] All right, the instrumentation seems to be working!"
|
||||
|
||||
all_done: test_build
|
||||
@echo "[+] All done! You can now use '../afl-clang-fast' to compile programs."
|
||||
|
||||
.NOTPARALLEL: clean
|
||||
|
||||
vpath % ..
|
||||
%.8: %
|
||||
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
|
||||
@echo .SH NAME >> ../$@
|
||||
@echo .B $* >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH SYNOPSIS >> ../$@
|
||||
@../$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH OPTIONS >> ../$@
|
||||
@echo .nf >> ../$@
|
||||
@../$* -h 2>&1 | tail -n +4 >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH AUTHOR >> ../$@
|
||||
@echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com>" >> ../$@
|
||||
@echo The homepage of afl++ is: https://github.com/vanhauser-thc/AFLplusplus >> ../$@
|
||||
@echo >> ../$@
|
||||
@echo .SH LICENSE >> ../$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ../$@
|
||||
ln -sf afl-clang-fast.8 ../afl-clang-fast++.8
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 afl-llvm-pass.dwo
|
||||
rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-fast*.8
|
||||
all:
|
||||
@echo please use GNU make, thanks!
|
||||
|
@ -15,9 +15,9 @@ typedef long double max_align_t;
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
@ -376,10 +376,10 @@ void MakeUniq(uint32_t now) {
|
||||
|
||||
}
|
||||
|
||||
void MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
bool MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
|
||||
TopologicalSort(ss, tt);
|
||||
if (TopoOrder.empty()) return;
|
||||
if (TopoOrder.empty()) return false;
|
||||
|
||||
for (uint32_t i : TopoOrder) {
|
||||
|
||||
@ -394,6 +394,10 @@ void MarkSubGraph(uint32_t ss, uint32_t tt) {
|
||||
|
||||
}
|
||||
|
||||
// Check if there is an empty path.
|
||||
if (NextMarked[tt].count(TopoOrder[0]) > 0) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void MarkVertice() {
|
||||
@ -417,14 +421,22 @@ void MarkVertice() {
|
||||
|
||||
timeStamp = 0;
|
||||
uint32_t t = 0;
|
||||
bool emptyPathExists = true;
|
||||
|
||||
while (s != t) {
|
||||
|
||||
MarkSubGraph(DominatorTree::idom[t], t);
|
||||
emptyPathExists &= MarkSubGraph(DominatorTree::idom[t], t);
|
||||
t = DominatorTree::idom[t];
|
||||
|
||||
}
|
||||
|
||||
if (emptyPathExists) {
|
||||
|
||||
// Mark all exit blocks to catch the empty path.
|
||||
Marked.insert(t_Pred[0].begin(), t_Pred[0].end());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return {marked nodes}
|
||||
|
22
llvm_mode/README.ctx.md
Normal file
22
llvm_mode/README.ctx.md
Normal file
@ -0,0 +1,22 @@
|
||||
# AFL Context Sensitive Branch Coverage
|
||||
|
||||
## What is this?
|
||||
|
||||
This is an LLVM-based implementation of the context sensitive branch coverage.
|
||||
|
||||
Basically every function gets it's own ID and that ID is combined with the
|
||||
edges of the called functions.
|
||||
|
||||
So if both function A and function B call a function C, the coverage
|
||||
collected in C will be different.
|
||||
|
||||
In math the coverage is collected as follows:
|
||||
`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1`
|
||||
|
||||
## Usage
|
||||
|
||||
Set the `AFL_LLVM_INSTRUMENT=CTX` or `AFL_LLVM_CTX=1` environment variable.
|
||||
|
||||
It is highly recommended to increase the MAP_SIZE_POW2 definition in
|
||||
config.h to at least 18 and maybe up to 20 for this as otherwise too
|
||||
many map collisions occur.
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user