Compare commits

...

513 Commits
2.61c ... 2.63c

Author SHA1 Message Date
fb8da3e4b1 push new version 2020-04-09 10:23:37 +02:00
a9c0f9a165 fix indention 2020-04-09 10:23:37 +02:00
4b5c4d58dc Update README.snapshot.md 2020-04-09 10:23:37 +02:00
b0e58b5b14 fixed critical whitespace 2020-04-09 10:23:37 +02:00
858c81a19b fix compile for MacOSX -DFORTIFY_SOURCE=2 is problematic 2020-04-09 10:23:37 +02:00
04360a35ed fix review comments by Heiko 2020-04-09 10:23:37 +02:00
c8ca944fac fix review comments by Heiko 2020-04-09 10:23:37 +02:00
b5e4d1a491 fix gcc_plugin Makefile (VPATH) 2020-04-09 10:23:37 +02:00
20cb846c95 Makefile cleanup 2020-04-09 10:23:37 +02:00
a1e531589e unicorn_mode/samples/persistent Makefile portable version 2020-04-09 10:23:37 +02:00
d6b680de48 remove todo 2020-04-09 10:23:37 +02:00
28314632bd fix travis - heiko test your changes on linux pls ;) 2020-04-09 10:23:37 +02:00
09ab904354 one more include move 2020-04-09 10:23:37 +02:00
5c0cf60ec1 fix damage in test.sh 2020-04-09 10:23:37 +02:00
698caed9c0 llvm_mode ctx: move function terminator instrumentation before skipping blocks 2020-04-09 10:23:37 +02:00
ae05f5c4b0 afl-fuzz: add usage info when no python support is there, use it in test.sh 2020-04-09 10:23:37 +02:00
d397bba6b2 llvm_mode android fix 2020-04-09 10:23:37 +02:00
7a6b66e684 fix limits.h include 2020-04-09 10:23:37 +02:00
e6daeef55c fix compilation in OpenBSD 2020-04-09 10:23:37 +02:00
c36c1b8992 update todo 2020-04-09 10:23:37 +02:00
1d1f575b5c add missing piece for CTX coverage 2020-04-09 10:23:37 +02:00
ecdffa03f8 added snapshot feature to documentation 2020-04-09 10:23:37 +02:00
6688184bfd argv_fuzzing Makefile: portable version 2020-04-09 10:23:37 +02:00
84a4fd40a0 fix travis 2020-04-09 10:23:37 +02:00
d37a195392 socket_fuzzing Makefile: make it portable 2020-04-09 10:23:37 +02:00
11e76af819 libdislocator: make Makefile portable 2020-04-09 10:23:37 +02:00
ed8c0d173e gcc_plugin: portable Makefile 2020-04-09 10:23:37 +02:00
c57fdbedaf gcc_plugin fix compile for USEMMAP 2020-04-09 10:23:37 +02:00
bd9676aa04 Android build fix proposal.
LTO flag is recognised but however broken on Android (tested with armv7 arch).
Thus giving the choice not to enable it.
In fortify mode, open required O_CREAT or O_TMPFILE when mode is set.
2020-04-09 10:23:37 +02:00
e5d0a9ecdf update readme 2020-04-09 10:23:37 +02:00
314debb799 ctx done 2020-04-09 10:23:37 +02:00
24ad714d0d update env with AFL_NO_SNAPSHOT 2020-04-09 10:23:37 +02:00
41225b53fa small fixes 2020-04-09 10:23:37 +02:00
5efd306f7b snapshot() in llvm mode 2020-04-09 10:23:37 +02:00
ccbcb5c8d3 added AFL_LLVM_INSTRUMENT, made USE_TRACE_PC obselete and llvm_mode Makefile fix, fixed for FUSELD (for LTO) 2020-04-09 10:23:37 +02:00
2f172d6c5a GNUmakefile: python config add --ldflags, silence tests 2020-04-09 10:23:37 +02:00
1eb81fdf36 unicorn_mode build script: find setuptools more reliably 2020-04-09 10:23:37 +02:00
62b6af693d Makefile bugfix macros are generally not expanded in shell calls 2020-04-09 10:23:37 +02:00
a49988afbf fix silly error with uname -s 2020-04-09 10:23:37 +02:00
03495beadb libtokencap, portable Makefile (for GNUmake and BSDmake) 2020-04-09 10:23:37 +02:00
079fdbf9bc portable version of Makefile (tested with bsdmake and GNUmake) 2020-04-09 10:23:37 +02:00
002e3840e6 update todo 2020-04-09 10:23:37 +02:00
96c558bec4 update todo 2020-04-09 10:23:37 +02:00
a267263420 unit tests cleaning 2020-04-09 10:23:37 +02:00
c14fd1ad18 code format, small improvements 2020-04-09 10:23:37 +02:00
88782ae43c custom mutator readme 2020-04-09 10:23:37 +02:00
70e777d031 no random timing for -s fixed_seed 2020-04-09 10:23:37 +02:00
9e1482ad04 fix make install regarding MANPAGES target 2020-04-09 10:23:37 +02:00
fef08192ad restore portable Makefiles 2020-04-09 10:23:37 +02:00
5488422471 fix UI bug for bit flip yields 2020-04-09 10:23:37 +02:00
e8e6dbf839 small enhancements and code-format 2020-04-09 10:23:37 +02:00
5602a09cc6 remove MaybeAlign 2020-04-09 10:23:37 +02:00
164a01e723 fix make install 2020-04-09 10:23:37 +02:00
f7f106c42a remove maybe_linking artifacts 2020-04-09 10:23:37 +02:00
7f817fe583 rename all 'Makefile' to 'GNUmakefile', use -Werror for -flto checks 2020-04-09 10:23:37 +02:00
5e66d95fbd better asan 2020-04-09 10:23:37 +02:00
d064b2e4af el no longer has to be used in loop 2020-04-09 10:23:37 +02:00
9d067d26da fix unit test case for long list 2020-04-09 10:23:37 +02:00
8e417ecb5c makefile asan fix 2020-04-09 10:23:37 +02:00
a9d072ad02 O3 again 2020-04-09 10:23:37 +02:00
5630c2e72c list testcase added 2020-04-09 10:23:37 +02:00
29ff59cc8a fixing unit tests (again) remove CFLAGS_FLTO, put LDFLAGS near the end 2020-04-09 10:23:37 +02:00
dab429521b added (broken) list test 2020-04-09 10:23:37 +02:00
48fc106905 added prealloc testcase 2020-04-09 10:23:37 +02:00
ee72d5d01d add Make rule for new unit test 2020-04-09 10:23:37 +02:00
378f4dd46d fix make target unit test (tested on Ubuntu 16.04) 2020-04-09 10:23:37 +02:00
2455f081fc llvm_mode: using MaybeAlign wrapper over the deprecated setter.
seems to be available even on LLVM 3.7
2020-04-09 10:23:37 +02:00
d40866add2 unittest for prealloc added 2020-04-01 14:39:03 +02:00
9ca8ff77f3 Merge branch 'master' of github.com:aflplusplus/aflplusplus into dev 2020-04-01 13:10:14 +02:00
e95ac10ff7 fix ASAN check 2020-04-01 13:10:07 +02:00
c7cf2c17a2 fix ASAN bulid for old gcc versions 2020-04-01 13:10:07 +02:00
29b1e30126 fixed asan mem limit 2020-04-01 13:10:07 +02:00
24b9eddc7e disable memory limits for ASAN build 2020-04-01 13:10:07 +02:00
effa766d4a fix cmocka fixup 2020-04-01 13:10:07 +02:00
b9783e44a3 cmocka mocks 2020-04-01 13:10:07 +02:00
35c817ccd0 mocking cmocka 1 for cmocka 0.x 2020-04-01 13:10:07 +02:00
77d68bc7bd old cmocka is old 2020-04-01 13:10:07 +02:00
6392a349ce add assert_ptr_equal fallback 2020-04-01 13:10:07 +02:00
4489dd24a8 typo fix 2020-04-01 13:10:07 +02:00
d374648ce3 docs 2020-04-01 13:10:07 +02:00
d611e7d50e next_p2 replaced by next_pow2 2020-04-01 13:10:07 +02:00
25d6d21617 code format 2020-04-01 13:10:07 +02:00
74b4096570 one less alloc 2020-04-01 13:10:07 +02:00
eca55be4fb minor changes 2020-04-01 13:10:07 +02:00
71372c4d2f fixed docu 2020-04-01 13:10:07 +02:00
a0693d466c try to fix forkserver 2020-04-01 13:10:07 +02:00
14d2456c35 fix gcc 2020-04-01 13:10:07 +02:00
c8bdf0790f reenabled custom mutator report 2020-04-01 13:10:07 +02:00
0b8a5cb4bb travis: dont fail on custom mutator - currently 2020-04-01 13:10:07 +02:00
8f98d5a8f8 fix unit test compilation 2020-04-01 13:10:07 +02:00
b83a2c1a00 make travis happy 2020-04-01 13:10:07 +02:00
5a4d4ad736 fixed bug in cmplog 2020-04-01 13:10:07 +02:00
5bc6dccbbd src doku is now markdown 2020-04-01 13:10:07 +02:00
42ee300e92 dropped make switches 2020-04-01 13:10:07 +02:00
582f5103d9 enabled fortify source 2020-04-01 13:10:07 +02:00
abef859925 Update regexp.dict 2020-04-01 13:10:07 +02:00
6eb79c28d1 Update regexp.dict 2020-04-01 13:10:07 +02:00
84a096561a tiny fixes 2020-04-01 13:10:07 +02:00
9a1f105869 fix ubuntu cmocka pkgname 2020-04-01 13:10:07 +02:00
677f2c6ca9 mutator docs 2020-04-01 13:10:07 +02:00
508230e91b code format 2020-04-01 13:10:07 +02:00
9cab515e58 added unittests to test.sh 2020-04-01 13:10:07 +02:00
514036898f added unit target to make help and README 2020-04-01 13:10:07 +02:00
19415f2554 Add test cases for the custom mutator (#276)
* Minor update

* Fix the soft link of `afl-clang-fast++`

* Add a test case for the custom mutator

- Update the Makefile in examples/custom_mutators
- Add a test program for testing the custom mutator
- Update test.sh for testing the custom mutator
- [TODO] Update the result checking criterias of the custom mutator in
test.sh

* Fix nullptr in the custom mutator

* Fix typo

* Fix invalid memory access bug in `afl_custom_pre_save` of example.c

* example.py: add deinit()

* python mutator: fix nullptr for python mutator data

* test.sh: "trusty-amd64" does not work well with "realpath". Use
"readlink -f" for Ubuntu instead.

* Fix heap allocation bug

- Reason: `afl->out_size` is not consistent with the actual allocation
of `afl->out_buf`. The deleted line in `src/afl-fuzz-one.c` may change
`afl->out_size`, but `afl->out_buf` is not changed

* test.sh: redirect command line output

* afl-fuzz-one.c: minor update

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2020-04-01 13:10:07 +02:00
710a29a1e0 fixed testcase 2020-04-01 13:10:07 +02:00
c36c34cf9e fixed example 2020-04-01 13:10:07 +02:00
e910c224da afl-fuzz-one.c: minor update 2020-04-01 13:10:07 +02:00
ea95453975 test.sh: redirect command line output 2020-04-01 13:10:07 +02:00
61ea398612 Fix heap allocation bug
- Reason: `afl->out_size` is not consistent with the actual allocation
of `afl->out_buf`. The deleted line in `src/afl-fuzz-one.c` may change
`afl->out_size`, but `afl->out_buf` is not changed
2020-04-01 13:10:07 +02:00
64e1d3a975 test.sh: "trusty-amd64" does not work well with "realpath". Use
"readlink -f" for Ubuntu instead.
2020-04-01 13:10:07 +02:00
50fc7327f2 python mutator: fix nullptr for python mutator data 2020-04-01 13:10:07 +02:00
71edae4a0f example.py: add deinit() 2020-04-01 13:10:07 +02:00
0dd8ed9171 Fix invalid memory access bug in afl_custom_pre_save of example.c 2020-04-01 13:10:07 +02:00
d568559f01 Fix typo 2020-04-01 13:10:06 +02:00
1e290542bb rebase 2020-04-01 13:10:06 +02:00
245304f593 Add a test case for the custom mutator
- Update the Makefile in examples/custom_mutators
- Add a test program for testing the custom mutator
- Update test.sh for testing the custom mutator
- [TODO] Update the result checking criterias of the custom mutator in
test.sh
2020-04-01 13:10:06 +02:00
be441dc176 upstream changes 2020-04-01 13:10:06 +02:00
da1a0249d7 merged dev 2020-04-01 13:10:06 +02:00
d07587885c added untitest to gitignore 2020-04-01 13:10:06 +02:00
376b45c199 code format 2020-04-01 13:10:06 +02:00
b247366c4e regec dict additions 2020-04-01 13:10:06 +02:00
7c383094d9 added unittest for unit_maybe_alloc 2020-04-01 13:10:06 +02:00
9721990507 code cleanup 2020-04-01 13:10:06 +02:00
452067ffca added read_timed 2020-04-01 13:10:06 +02:00
3ce5efc44b llvm_mode/Makefile: replace lexical version comparison with a numerical one 2020-04-01 13:10:06 +02:00
1e8c1a4c46 review adaptions for afl-llvm-pass 2020-04-01 13:10:06 +02:00
b53ec1b247 afl-llvm-pass.so.cc: fix compile for llvm 3.8.0 @Marc: please review 2020-04-01 13:10:06 +02:00
4ccfbe4e5a .gitignore: add afl-ld and ld 2020-04-01 13:10:06 +02:00
7698c051aa qemu_mode: compiler warnings, strncpy() leave one byte for terminator 2020-04-01 13:10:06 +02:00
1950f09bde qemu_mode: fix more compiler warnings 2020-04-01 13:10:06 +02:00
e41b03eb30 qemu_mode: silence two compiler warnings 2020-04-01 13:10:06 +02:00
98545f30aa code format 2020-04-01 13:10:06 +02:00
81873d97f8 error handling for custom mutators 2020-04-01 13:10:06 +02:00
cda56ca129 types.h: silence some compiler warnings regarding redeclaration of
likely/unlikely
2020-04-01 13:10:06 +02:00
ab5e0703da tiny changes in custom mut api 2020-04-01 13:10:06 +02:00
f370ef38c4 alloc-inl.h/ck_maybe_grow(): restore original exponential allocs 2020-04-01 13:10:06 +02:00
1119a2e185 alloc-inl.h/ck_maybe_grow() back to size_t, reimplement overflow check 2020-04-01 13:10:06 +02:00
9d7ac3d99f alloc_inl.h/ck_maybe_grow(): fix compiler warning 2020-04-01 13:10:06 +02:00
0732e66da9 gcc_plugin: fix compiler warnings regarding -O and FORTIFY_SOURCE 2020-04-01 13:10:06 +02:00
e56e2f4c18 llvm_mode: fix compiler warnings FORTIFY_SOURCE needs -O 2020-04-01 13:10:06 +02:00
23d9649aec making 'CFLAGS="-m32" make source-only tests' work 2020-04-01 13:10:06 +02:00
738a245c3e fix warning in afl-fuzz-run, tested with '-m32' also 2020-04-01 13:10:06 +02:00
78d73720a2 fix detection compiles (e.g. python) when using CFLAGS="-m32" 2020-04-01 13:10:05 +02:00
e59282fe20 if exponential growth is too much, don't doo it 2020-04-01 13:10:05 +02:00
9785b15ed2 more custom mutator remodelling 2020-04-01 13:10:05 +02:00
8c94a3d177 added nullptr fix by h1994st 2020-04-01 13:10:05 +02:00
5bd8aa489b fixed leak 2020-04-01 13:10:05 +02:00
e71c2937de code format 2020-04-01 13:10:05 +02:00
3d6c58df53 part1 make it compilable for llvm 3.8.0 (ubuntu 16.04) 2020-04-01 13:10:05 +02:00
34c090a31d add CFI sanitizer 2020-04-01 13:10:05 +02:00
762421b355 less allocs 2020-04-01 13:10:05 +02:00
b7f3d180aa not allocating paths anymore 2020-04-01 13:10:05 +02:00
71f8cc9dd2 almost 2020-04-01 13:10:05 +02:00
3c7bc6fd42 Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-04-01 12:53:10 +02:00
af60844aea fix ASAN bulid for old gcc versions 2020-04-01 12:53:03 +02:00
c4c13dd235 fix ASAN check 2020-04-01 12:52:54 +02:00
ba4f0186dd fixed asan mem limit 2020-04-01 12:43:26 +02:00
a5c09e4c11 disable memory limits for ASAN build 2020-04-01 12:19:54 +02:00
c7818714ac fix cmocka fixup 2020-04-01 09:42:40 +02:00
cec3d74497 cmocka mocks 2020-04-01 03:39:36 +02:00
10b226418c mocking cmocka 1 for cmocka 0.x 2020-04-01 03:20:22 +02:00
c843085a28 old cmocka is old 2020-04-01 02:59:19 +02:00
101c5a275f add assert_ptr_equal fallback 2020-04-01 02:28:54 +02:00
acf4b0981e typo fix 2020-04-01 02:09:33 +02:00
98c0908185 docs 2020-04-01 02:07:52 +02:00
ead3701f5b next_p2 replaced by next_pow2 2020-04-01 02:03:46 +02:00
0349b0a735 code format 2020-04-01 02:00:03 +02:00
11cad9fb20 one less alloc 2020-04-01 01:58:34 +02:00
7f44fec0a5 minor changes 2020-04-01 01:55:13 +02:00
d4c8a2058d fixed docu 2020-04-01 01:38:45 +02:00
d73e63bd70 try to fix forkserver 2020-04-01 01:24:44 +02:00
d0d5518ea8 fix gcc 2020-03-31 18:06:14 +02:00
822e75f7c2 reenabled custom mutator report 2020-03-31 14:01:22 +02:00
08b6b4ec4e travis: dont fail on custom mutator - currently 2020-03-31 07:37:30 +02:00
3253e3f315 fix unit test compilation 2020-03-31 07:14:25 +02:00
e58e54c2db make travis happy 2020-03-31 04:51:38 +02:00
0a7dc10dd3 fixed bug in cmplog 2020-03-31 04:22:22 +02:00
3914aec72f src doku is now markdown 2020-03-31 03:41:51 +02:00
9b63fc758e dropped make switches 2020-03-31 03:22:46 +02:00
d3130ace30 enabled fortify source 2020-03-31 02:41:11 +02:00
daa09a5fbb Update regexp.dict 2020-03-31 01:41:16 +02:00
a249dadfb0 Update regexp.dict 2020-03-31 01:41:16 +02:00
64e9f1f3a2 tiny fixes 2020-03-30 23:53:10 +02:00
9110097e11 fix ubuntu cmocka pkgname 2020-03-30 18:55:54 +02:00
ac48b58184 mutator docs 2020-03-30 18:46:12 +02:00
8f5fb47082 code format 2020-03-30 18:38:39 +02:00
a58382d3ff added unittests to test.sh 2020-03-30 18:37:16 +02:00
5ef8e3cf29 Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-03-30 18:22:43 +02:00
6544014ced Add test cases for the custom mutator (#276)
* Minor update

* Fix the soft link of `afl-clang-fast++`

* Add a test case for the custom mutator

- Update the Makefile in examples/custom_mutators
- Add a test program for testing the custom mutator
- Update test.sh for testing the custom mutator
- [TODO] Update the result checking criterias of the custom mutator in
test.sh

* Fix nullptr in the custom mutator

* Fix typo

* Fix invalid memory access bug in `afl_custom_pre_save` of example.c

* example.py: add deinit()

* python mutator: fix nullptr for python mutator data

* test.sh: "trusty-amd64" does not work well with "realpath". Use
"readlink -f" for Ubuntu instead.

* Fix heap allocation bug

- Reason: `afl->out_size` is not consistent with the actual allocation
of `afl->out_buf`. The deleted line in `src/afl-fuzz-one.c` may change
`afl->out_size`, but `afl->out_buf` is not changed

* test.sh: redirect command line output

* afl-fuzz-one.c: minor update

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2020-03-30 18:21:03 +02:00
3fcb3e2ed3 fixed testcase 2020-03-30 18:20:20 +02:00
caebc9347f added unit target to make help and README 2020-03-30 17:45:17 +02:00
1f257c5875 fixed example 2020-03-30 16:46:54 +02:00
e2a3de71ca afl-fuzz-one.c: minor update 2020-03-30 16:46:54 +02:00
57a0134b0c test.sh: redirect command line output 2020-03-30 16:46:54 +02:00
d9b18ec853 Fix heap allocation bug
- Reason: `afl->out_size` is not consistent with the actual allocation
of `afl->out_buf`. The deleted line in `src/afl-fuzz-one.c` may change
`afl->out_size`, but `afl->out_buf` is not changed
2020-03-30 16:46:54 +02:00
6c14415664 test.sh: "trusty-amd64" does not work well with "realpath". Use
"readlink -f" for Ubuntu instead.
2020-03-30 16:46:54 +02:00
567b3985ab python mutator: fix nullptr for python mutator data 2020-03-30 16:46:54 +02:00
45561d552e example.py: add deinit() 2020-03-30 16:46:54 +02:00
fbd5bd8f37 Fix invalid memory access bug in afl_custom_pre_save of example.c 2020-03-30 16:46:54 +02:00
048beb752d Fix typo 2020-03-30 16:46:53 +02:00
87621b6345 rebase 2020-03-30 16:46:50 +02:00
ff14dfc0fc Add a test case for the custom mutator
- Update the Makefile in examples/custom_mutators
- Add a test program for testing the custom mutator
- Update test.sh for testing the custom mutator
- [TODO] Update the result checking criterias of the custom mutator in
test.sh
2020-03-30 16:46:11 +02:00
c624831717 upstream changes 2020-03-30 16:46:05 +02:00
c697a003d1 merged dev 2020-03-30 16:45:13 +02:00
6bdd7a1609 added untitest to gitignore 2020-03-30 16:08:07 +02:00
50a195fe59 code format 2020-03-30 16:07:25 +02:00
738016952f Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-03-30 16:01:33 +02:00
209aa25d27 added unittest for unit_maybe_alloc 2020-03-30 16:01:29 +02:00
1279c935e2 regec dict additions 2020-03-30 11:33:42 +02:00
28e5a8031c code cleanup 2020-03-30 00:50:32 +02:00
f4844e2c0c added read_timed 2020-03-30 00:50:14 +02:00
ef3a13fa63 llvm_mode/Makefile: replace lexical version comparison with a numerical one 2020-03-29 09:48:01 +02:00
699f769385 review adaptions for afl-llvm-pass 2020-03-28 23:01:12 +01:00
2548b657d8 afl-llvm-pass.so.cc: fix compile for llvm 3.8.0 @Marc: please review 2020-03-28 20:25:00 +01:00
02d19dafb2 .gitignore: add afl-ld and ld 2020-03-28 14:23:54 +01:00
78009d9d07 qemu_mode: compiler warnings, strncpy() leave one byte for terminator 2020-03-28 14:15:04 +01:00
2aa7ddf1a8 qemu_mode: fix more compiler warnings 2020-03-28 13:51:35 +01:00
3c142efecf qemu_mode: silence two compiler warnings 2020-03-28 13:38:49 +01:00
23b3e3c84d Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-03-28 13:06:05 +01:00
8b8600fdab types.h: silence some compiler warnings regarding redeclaration of
likely/unlikely
2020-03-28 13:05:26 +01:00
1938a12222 code format 2020-03-28 12:59:41 +01:00
4c11ef5d20 error handling for custom mutators 2020-03-28 12:58:56 +01:00
6ac40e2cc5 Merge branch 'dev' of https://github.com/vanhauser-thc/AFLplusplus into dev 2020-03-28 12:16:01 +01:00
5625e059e1 alloc-inl.h/ck_maybe_grow(): restore original exponential allocs 2020-03-28 12:15:01 +01:00
11767bec0e tiny changes in custom mut api 2020-03-28 11:55:10 +01:00
7a92bf974d alloc-inl.h/ck_maybe_grow() back to size_t, reimplement overflow check 2020-03-28 11:01:29 +01:00
fc46e9c9a0 alloc_inl.h/ck_maybe_grow(): fix compiler warning 2020-03-28 10:23:11 +01:00
7a752d0795 gcc_plugin: fix compiler warnings regarding -O and FORTIFY_SOURCE 2020-03-28 10:00:23 +01:00
0cff53785b llvm_mode: fix compiler warnings FORTIFY_SOURCE needs -O 2020-03-28 09:54:40 +01:00
4ad885001a making 'CFLAGS="-m32" make source-only tests' work 2020-03-28 09:31:30 +01:00
a0dec909e7 fix warning in afl-fuzz-run, tested with '-m32' also 2020-03-28 08:38:50 +01:00
2a660b19a7 fix detection compiles (e.g. python) when using CFLAGS="-m32" 2020-03-28 08:32:54 +01:00
8992c44c41 if exponential growth is too much, don't doo it 2020-03-28 05:01:01 +01:00
53fd8fe6ea more custom mutator remodelling 2020-03-28 04:57:44 +01:00
0059d16731 added nullptr fix by h1994st 2020-03-28 01:14:24 +01:00
18bc344cf5 fixed leak 2020-03-28 00:44:52 +01:00
e04f4b3f20 code format 2020-03-27 23:30:15 +01:00
5e389a0970 Less allocs 2020-03-27 23:24:42 +01:00
1141459607 less allocs 2020-03-27 23:23:11 +01:00
02659df6ba not allocating paths anymore 2020-03-27 23:06:57 +01:00
14bd424d2a almost 2020-03-27 21:59:08 +01:00
7c76b7db04 part1 make it compilable for llvm 3.8.0 (ubuntu 16.04) 2020-03-27 21:03:28 +01:00
a7553eae28 add CFI sanitizer 2020-03-27 12:09:06 +01:00
5cc50bb979 important llvm_mode Makefile fix 2020-03-27 11:06:06 +01:00
932eae7343 example fixed 2020-03-27 11:06:06 +01:00
604f122819 docu 2020-03-27 11:06:06 +01:00
d6a7630fe2 more api 2020-03-27 11:06:06 +01:00
fc4b03ee74 Code Format (#275) 2020-03-27 11:06:06 +01:00
e9c7610cb7 edited custom mutator pre_save api 2020-03-27 11:06:06 +01:00
3c3a5aa503 updated with required changes 2020-03-27 11:06:06 +01:00
6d3dc83c5d code format 2020-03-27 11:06:06 +01:00
89512d4e05 fixed call of custom mutators 2020-03-27 11:06:06 +01:00
b1d71136b0 fixed typos in README.md 2020-03-27 11:06:06 +01:00
8cf47f2425 add "time without finds" to afl-whatsup 2020-03-27 11:06:06 +01:00
c75b403bb7 fix doc link 2020-03-27 11:06:06 +01:00
ae284610cf important llvm_mode Makefile fix 2020-03-27 10:08:09 +01:00
5a7d33330a example fixed 2020-03-26 19:48:26 +01:00
12a9a1001e docu 2020-03-26 19:47:16 +01:00
97a1af39f7 more api 2020-03-26 19:44:44 +01:00
6832435326 Code Format (#275) 2020-03-26 18:47:48 +01:00
62bb94c50b Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-03-25 21:54:59 +01:00
eeb7e12b9f edited custom mutator pre_save api 2020-03-25 21:54:52 +01:00
f796537712 Merge pull request #272 from ashiscs/master
fixed typos in README.md
2020-03-25 17:32:32 +01:00
469446a02b updated with required changes 2020-03-25 19:35:38 +05:30
b24ef50f7b Merge pull request #271 from fuzzah/aflpp_time_without_finds
add "time without finds" to afl-whatsup
2020-03-25 12:50:42 +01:00
f6466214c6 code format 2020-03-25 11:31:01 +01:00
9c4d32b5b8 fixed call of custom mutators 2020-03-24 22:40:14 +01:00
50be709e91 fixed typos in README.md 2020-03-25 01:21:02 +05:30
2e060f856d Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-03-24 18:46:43 +01:00
c9a2401983 fix doc link 2020-03-24 18:46:25 +01:00
ce58790fc0 add "time without finds" to afl-whatsup 2020-03-24 15:12:08 +03:00
7f3e04cbc4 fix doc link 2020-03-24 08:44:18 +01:00
3fb346fe29 Merge pull request #269 from AFLplusplus/dev
Dev
2020-03-23 20:42:10 +01:00
36213dba7d Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-03-23 20:19:20 +01:00
65817144ac include afl-llvm-rt.o not only when linking 2020-03-23 20:19:07 +01:00
82432195a8 Merge pull request #266 from AFLplusplus/dev 2020-03-23 18:19:20 +01:00
77b81e7361 custom mutators might work again like this 2020-03-23 18:18:54 +01:00
83f925ccc9 unsafer 2020-03-23 15:02:26 +01:00
39208eeb9a typo 2020-03-23 12:06:43 +01:00
f32d1022bd surgical_havoc_mutate() in custom mutator helpers 2020-03-23 10:47:17 +01:00
ee9447de01 libasan.so is not a thing. libclang-rt.asan-ARCH.so is the asan DSO and it is not linked by default. Search for __asan_init instead. 2020-03-23 10:09:55 +01:00
dcfc24501b update readme 2020-03-23 10:05:08 +01:00
e65e723e03 update readme 2020-03-23 09:50:12 +01:00
94e30002e7 better man page for afl-clang-* 2020-03-23 09:25:05 +01:00
37603272be more fixes and code-format 2020-03-23 08:58:17 +01:00
4263519479 more fixes 2020-03-23 08:48:57 +01:00
db302ff18b minor fixes 2020-03-23 08:44:27 +01:00
cbde30e9d4 less branches, cleanup 2020-03-23 00:14:03 +01:00
c0fd8f4e15 Merge pull request #265 from devnexen/unicorn_python3_4_mac
Enforcing python3 for Mac too.
2020-03-22 19:09:43 +01:00
d39e9ea11c little performance enhancements 2020-03-22 19:06:39 +01:00
5b64681867 a little bit more performance 2020-03-22 18:27:04 +01:00
0132657432 Enforcing python3 for Mac too. 2020-03-22 12:31:58 +00:00
aac7c7d75d detect arm in build_qemu_support.sh 2020-03-22 12:09:52 +01:00
bd239d7e3d nice -n -20 to commit test script 2020-03-22 11:28:09 +01:00
da1f2f3c17 fix travis 2020-03-22 10:24:29 +01:00
7374af51d1 silly, silly typo 2020-03-22 10:07:59 +01:00
38fa2fe0b1 add commit test script test/checkcommit.sh 2020-03-22 09:32:13 +01:00
5a0cc43ee1 all afl msgs to stdout and only read AFL_BENCH_JUST_ONE once 2020-03-22 09:26:46 +01:00
f08a3fedf6 renamed UB to rand_below 2020-03-21 22:26:13 +01:00
5cf3426834 remove debug code 2020-03-21 22:17:57 +01:00
96736309a7 support for arm platform when building qemu 2020-03-21 22:11:07 +01:00
42ece199c8 revert test.sh patch 2020-03-21 22:04:52 +01:00
54d01fec43 moved string formatting to header 2020-03-21 21:48:52 +01:00
f8d717d195 test.sh fix 2020-03-21 21:42:32 +01:00
c6db05c5ae test.sh with -no-pie 2020-03-21 21:10:38 +01:00
6f78b67f03 adjusted int_bufs 2020-03-21 20:28:01 +01:00
a5af81506f qemu_mode/unicorn_mode scripts: fix '==' in '[' 2020-03-21 19:31:15 +01:00
087bc6daeb qemu_mode and unicorn_mode build scripts: replace type with command -v 2020-03-21 19:22:55 +01:00
f18dbb0b40 afl-gotcpu.c: compielr warning fixed: initialize variable v2 2020-03-21 19:13:39 +01:00
6cbd0f1faf avoid calling awk for 'which' replacement, use POSIX 'command -v' instead 2020-03-21 18:51:43 +01:00
dcd9cd638b fix stat display 2020-03-21 17:42:00 +01:00
350530f664 unicorn build script: list all missing prereqs in one invocation,
replace which with type
2020-03-21 10:59:58 +01:00
dabce05ec6 qemu_mode/build script: add more missing prereqs 2020-03-21 10:46:23 +01:00
993bf03af9 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-03-21 10:36:18 +01:00
2508008b53 qemu_mode, build script: avoid which, add patch to prereqs, list all
missing prereqs in one invocation
2020-03-21 10:31:39 +01:00
a0012c9e82 forgot readme for ngram 2020-03-20 17:56:24 +01:00
c63956b8ec Merge branch 'dev' of https://github.com/vanhauser-thc/AFLplusplus into dev 2020-03-20 17:32:42 +01:00
6965797286 unicorn: increase timeout for unicorn test in build script 2020-03-20 17:31:48 +01:00
5a74cffa0f added llvm_mode ngram coverage 2020-03-20 17:10:44 +01:00
f21ff8bac8 show cycles_without_finds in afl-whatsup 2020-03-20 12:19:22 +01:00
5d932398df expose cycles_wo_finds in fuzzer_stats 2020-03-20 09:44:51 +01:00
5532fc1102 added missing descriptions of entries in fuzzer_stats 2020-03-20 09:28:43 +01:00
60d66ebc0d clean was missing ld symlink 2020-03-20 09:06:54 +01:00
29853549c3 add RARE schedule. also fixes doc_path 2020-03-20 08:54:09 +01:00
d0b5cd64c3 install llvm_mode READMEs 2020-03-19 23:55:28 +01:00
cd4243b6ad update doc 2020-03-19 23:40:45 +01:00
cd2be88707 travis for dev branch 2020-03-19 23:29:33 +01:00
5b9d306cdf no more (?) statics 2020-03-19 22:54:09 +01:00
0fa47bb867 removed unneeded func 2020-03-19 21:33:17 +01:00
b22e890ec2 fixed resize; removed more statics 2020-03-19 21:32:08 +01:00
b6fa63abdf code format 2020-03-19 19:23:58 +01:00
51a346bcbe 50% less globals 2020-03-19 19:22:57 +01:00
fd9587d26e Merge pull request #262 from rish9101/remove_alarm
Port the fauxserver changes to afl-cmplog and code format
2020-03-19 17:01:57 +01:00
0e1d82dd9f describe branches setup in README 2020-03-19 15:27:12 +01:00
be261b3e69 moved repository to https://github.com/AFLplusplus/AFLplusplus and updated links 2020-03-19 15:20:39 +01:00
f6847b0314 test.sh: replace 'which' with 'type' 2020-03-19 00:19:25 +01:00
eca6bdb85d afl-cmin: replace 'which' with 'type' 2020-03-19 00:15:48 +01:00
a3bd1c71ca Makefiles: replace 'which' with 'type' 2020-03-18 23:51:54 +01:00
b19039ba8b Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-03-18 22:56:19 +01:00
94a4cc8415 Makefiles: prefer POSIX 'type' over 'which' for checking 2020-03-18 22:55:14 +01:00
2e4fda6d4c fix #261 2020-03-18 21:18:55 +01:00
cd7e234445 try to fix regression due to rtn cmplog 2020-03-18 21:07:31 +01:00
a5e747af14 rework docs installation 2020-03-18 17:26:21 +01:00
5060861545 qemu_mode/libcompcov/Makefile install: fix installation of README 2020-03-18 16:26:54 +01:00
992cf3dd25 libtokencap Makefile install: forgot -T for README 2020-03-18 16:23:54 +01:00
1dee73cdde libtokencap: install correct README without name collision 2020-03-18 16:19:14 +01:00
3aa7242925 added mmopt power schedule 2020-03-17 21:42:36 +01:00
4009f3a987 fix reading env vars in afl-fuzz 2020-03-17 21:02:06 +01:00
cfd451c6f3 cmplog was neither quiet nor where its llvm passes installed 2020-03-17 16:26:51 +01:00
8e07fbf636 cmplog was neither quiet nor where its llvm passes installed 2020-03-17 16:26:36 +01:00
dae249dc71 minor fix to qemu_persistent_hook example 2020-03-17 16:10:34 +01:00
e194acdd79 PR #257 from chibinz, enhance afl-whatsup, (adapted for portability) 2020-03-17 14:26:08 +01:00
287d430fcf better explain AFL_QEMU_DEBUG_MAPS 2020-03-17 12:37:20 +01:00
d1d2fceed8 Port the fauxserver changes to afl-cmplog and code format 2020-03-17 15:19:24 +05:30
8cc39a3590 fix link in readme 2020-03-17 09:01:55 +01:00
a57896a7ce fixed segfault on early bailout 2020-03-17 00:00:36 +01:00
35720304be not all opt are compiled with polly support 2020-03-16 20:10:42 +01:00
09b2565b1b fix broken MOpt mode that was broken by Dominiks no-global patch :p 2020-03-16 20:09:46 +01:00
5b9335be10 fix compilation for Darwin/MacOSX 2020-03-16 14:04:21 +01:00
9ce0617cda fix for instrim with and without AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK 2020-03-16 07:28:31 +01:00
61ba214f19 print a completed UI screen on exit without bugs :) 2020-03-15 22:51:22 +01:00
bfe076748b fix test failure with qemu compcov 2020-03-15 21:42:04 +01:00
070412b9c1 Merge pull request #259 from devnexen/afl_globals_little_tweaks
Just compute the current len on env comparison once.
2020-03-15 20:03:27 +01:00
ccb21a745d Just compute the current len once.
Fix env var types assignments.
2020-03-15 18:57:18 +00:00
87599de782 fix errors in last commit (u8)afl_get_env 2020-03-15 19:39:03 +01:00
126d1f1cd1 Move afl-fuzz related env variables into afl_state_t (#252)
* Move afl-fuzz related env variables into afl_state_t

* Move the env variables assignment from fuzz_init and code Format

* Fix typo

* Remove redundant env variables from afl_env struct

* Rename function to read_afl_environment
2020-03-15 18:29:23 +01:00
7685893cdb fix afl-fuzz-document 2020-03-15 17:09:52 +01:00
f9f163e48f fix afl-fuzz-document 2020-03-15 17:07:06 +01:00
15ba6249fc fauxserver 2020-03-15 17:02:48 +01:00
f3799f94bf fix compiler warning on MacOS 2020-03-14 16:40:05 +01:00
e77c431582 fix compilation under FreeBSD: ugly name clash of LIST_FOREACH (FreeBSDs fault) 2020-03-14 13:21:39 +01:00
338daa1282 Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-03-14 11:45:25 +01:00
c616fcafe8 fix some compiler warnings from Open/FreeBSD 2020-03-14 11:44:21 +01:00
08fe1e2cd7 afl-common.c: fix my error: argv is a copy (ck_alloc based)
Now unicorn_mode works with ASAN_BUILD and _WANT_ORIGINAL_AFL_ALLOC
and DEBUG_BUILD also.
2020-03-13 20:37:39 +01:00
746a2a0ed0 afl-fuzz-init.c, afl-fuzz.c: fix more wrong free() calls (found with
ASAN_BUILD=1 CFLAGS="-D_WANT_ORIGINAL_AFL_ALLOC -DDEBUG_BUILD")
2020-03-13 17:23:23 +01:00
d2787519e3 afl-common.c: ... but that breaks unicorn_mode, which it should not. 2020-03-13 10:06:02 +01:00
23d0cea3c9 afl-common.c: avoid AFL++'s allocation API for libc's argv[] and reduce
complexity for cwd
2020-03-13 01:21:07 +01:00
530bd2b341 test.sh: make afl-cmin.bash test dependent on bash 2020-03-12 22:52:20 +01:00
8adc2648f8 fix afl-common.c for *BSD 2020-03-12 21:43:53 +01:00
0c45918d54 Fixed typo (#253) 2020-03-11 22:53:50 +01:00
288432843b updated README, ideas and a missing clean in Makefile 2020-03-11 12:03:44 +01:00
684f4dd1c4 honor afl_quiet on env var checks + code-format 2020-03-11 11:42:57 +01:00
d8d89507b5 afl-cmin delete output directory when aborted 2020-03-11 11:25:58 +01:00
f1ef398909 remove wrong call to write_to_file when aborted by user 2020-03-11 11:11:22 +01:00
66e8faaaa9 Fix typo (#247) 2020-03-11 00:48:52 +01:00
f17a3dde1a Replace timer with select in forkserver, where possible (#246) 2020-03-11 00:34:51 +01:00
88ced831c1 forkserver defaults 2020-03-10 22:56:26 +01:00
cc1d6b33b1 unified pointer placement 2020-03-10 22:04:05 +01:00
2832cb643d removed debug output 2020-03-10 16:27:28 +01:00
cd377f3d99 Replace alarms with select and threads (#243)
* Use select to monitor forkserver for timeouts instead of alarm

* Remove redundent conditons in select monitoring of fdsin forkserver and cmplog

* Replace SIGALARM with POSIX timers in afl-fuzz-run

* Make changes to Makefile to use POSIX timers

* Resolve Merge Conflicts and rename variables accordingly

* Change forkserver and cmplog to handle exec_tmout = 0

* Handle timeout function bug rectify

* Add error handling to afl-fuzz run timers

* Add timer_delete to afl-fuzz-run

* Remove memory leaks
2020-03-10 13:07:29 +01:00
0def6e3471 this should fix travis 2020-03-10 07:18:23 +01:00
1148a2d0d1 document new environment variables and code format 2020-03-10 07:14:42 +01:00
38d9aedb26 code-format - and afl-cmin/afl-showmap was fixed in the bugfix for afl-tmin 2020-03-10 06:54:31 +01:00
1467776a3f imported InsTrim algo fix 2020-03-10 06:47:11 +01:00
f678731234 afl-tmin is fixed via default initialization in forkserver 2020-03-10 06:44:24 +01:00
e04d2a6efa removed unused vars 2020-03-09 21:58:39 +01:00
1136e887bd now wiht 90% less leaks 2020-03-09 21:34:11 +01:00
416020daef quickfix for first big bug that use_stdin was not correctly initialized and could not be set 2020-03-09 19:42:23 +01:00
73a1b39446 quickfix for first big bug that use_stdin was not correctly initialized and could not be set 2020-03-09 19:40:59 +01:00
253bbf3a5c replaced free with ck_free 2020-03-09 19:36:02 +01:00
782cffb130 fixed numerous leaks 2020-03-09 19:30:26 +01:00
a24352ddfd fix leaks 2020-03-09 15:52:14 +01:00
2f41663673 copyleft note 2020-03-09 14:43:40 +01:00
cdd1dd3d20 changelog 2020-03-09 14:37:34 +01:00
dea1dbfba4 updated changelog and todo 2020-03-09 12:33:06 +01:00
988a32ced5 code-format 2020-03-09 12:21:54 +01:00
188a6f5ec5 disable leaksanitizer when "make" ... more 2020-03-09 12:17:59 +01:00
aa4050d406 disable leaksanitizer when "make" 2020-03-09 12:04:35 +01:00
581097d58d expanded test-instr to also work with input files via "-f @@" and changed the test.sh values 2020-03-09 11:39:12 +01:00
dba3595c0a AFL without globals (#220)
* moved globals to afl, shm and fsrv 

* moved argv to afl state, less bugs

* fixed unicorn docu

* lists everywhere

* merged custom mutators

* fixed leaks in afl-fuzz
2020-03-09 11:24:10 +01:00
c159b872ef removed warning in afl-gcc-pass.so.cc 2020-03-09 11:23:29 +01:00
df74edeb45 more honoring be_quiet 2020-03-09 11:08:50 +01:00
dcf7d85cba honor no_quiet for missing llvm_mode output, also print to stderr with afl-*-rt.o.c instead of stdout for errors plus two potential bad free() fixes 2020-03-09 10:56:53 +01:00
8e953d9931 Merge pull request #240 from rish9101/refactor
Remove get_cut_time function from multiple places and refactor code
2020-03-09 09:30:25 +01:00
9f89bbd5ec reactivated LTO persistent mode to test.sh 2020-03-09 08:51:37 +01:00
6a6dd84b39 more detail to the fact that LTO mode can fail easily 2020-03-09 08:33:08 +01:00
36ce9c1fb9 more code format 2020-03-09 08:30:28 +01:00
0581f6ec00 bug fixes to afl-ld and intensive README.lto.md update on errors and how to do the steps by hand, plus global code format 2020-03-09 08:27:23 +01:00
1a582d54e5 Remove get_cut_time function from multiple places and refactor code 2020-03-09 10:04:32 +05:30
a3161b902e fix null ptr deferef in pre_save python mutator call 2020-03-08 22:02:57 +01:00
783f3b0957 afl-ld fixes for -L/-l .a libary loads 2020-03-08 19:12:04 +01:00
8ff0161d58 "fixed" symbol multiply defined problems with LTO 2020-03-08 18:20:28 +01:00
9f7bcca91e mark AFL_PYTHON_ONLY deprecated 2020-03-08 16:56:44 +01:00
891f6985ed Merge pull request #238 from h1994st/master
Two new hooks for the custom mutator
2020-03-08 12:38:01 +01:00
98ffef26dc Merge pull request #239 from 0x1eadbead/fix-qemu-32-on-64
fix qemu persistent mode for 32-bit target on 64-bit host
2020-03-08 11:50:44 +01:00
81179b4829 fix qemu persistent mode for 32-bit target on 64-bit host 2020-03-08 13:39:06 +03:00
e7bc3e09a3 Update .gitignore 2020-03-07 16:30:31 -05:00
8f93cf5c55 Add two new hooks for the custom mutator
- `afl_custom_queue_get` and `afl_custom_queue_new_entry`
- Update the corresponding document and examples
2020-03-07 16:28:48 -05:00
dc0b2dda5e Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-03-07 10:29:14 -05:00
ed5d65b54f solve linking error when python is not available 2020-03-07 14:26:33 +01:00
172d384bf2 custom havoc mutation 2020-03-07 12:11:06 +01:00
1e30c3a941 afl-tmin hang mode added 2020-03-07 03:40:42 +01:00
a10a3f2fa7 Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-03-06 16:28:26 -05:00
2287534ec6 Merge branch 'master' of github.com:vanhauser-thc/AFLplusplus 2020-03-06 21:23:54 +01:00
27d6d35893 small fix to run cmplog binaries outside afl-fuzz 2020-03-06 21:23:47 +01:00
13429d204d adapt child handling to nawk from *BSD 2020-03-06 20:57:28 +01:00
0d4f2da8db terminate afl-cmin early when signalled SIGINT 2020-03-06 19:33:02 +01:00
47fdbf3817 Merge pull request #235 from antonio-morales/patch-1
Fixing 2 little mistakes
2020-03-06 16:53:10 +01:00
1d4a3c87f5 cmplog routines instrumentation for qemu mode on x86 2020-03-06 16:43:18 +01:00
c18f6c2618 Fixing 2 little mistakes
This example doesn't compile due to two little errors:
- There is a missing semicolon
- "data" array doesn't exist. I think "buf" should be used instead.
2020-03-06 16:09:43 +01:00
6e8f249b20 fix #227 2020-03-05 20:43:28 +01:00
3ac568c40c Fix leaks when stopping afl (#228) 2020-03-05 20:23:04 +01:00
90409f383a added AFL_QUIET - be_quiet to afl-showmap and small changes to test.sh 2020-03-05 11:36:37 +01:00
cc72f5dfd0 clarify -N option 2020-03-05 11:04:55 +01:00
6d620f5e0c fix travis 2020-03-05 11:03:36 +01:00
9d686ba523 Add LTO collision free llvm_mode (#223)
* first new implementation, only works with AFL_DONT_OPTIMIZE

* bug hunting

* interim commit

* finalized LTO non-collision solution

* update documentation

* merge resulted in some problems, fixing these

* added lto env to env check

* fixed llvm weirdness to messes up our instrumentation due CFG rewrite optimizations

* all llvm instrumentation issues have been resolved! :-)

* llvm 9 is required (so far)

* update lto readme
2020-03-05 10:52:26 +01:00
9e5c4973eb Fix variable name 2020-03-04 14:58:29 -05:00
70a67ca67d fix null ptr deref before trim_case_custom call 2020-03-04 19:28:29 +01:00
e43473faef Merge pull request #221 from h1994st/master
Uniform Python and custom mutator API
2020-03-04 18:38:03 +01:00
38e7dd2b9e Update examples of the custom mutator
- Merge `examples/python_mutators` into `examples/custom_mutators`
- Remove `examples/python_mutators`
- Update existing examples to demonstrate new APIs
2020-03-04 01:09:37 -05:00
42ce48db39 Fix typo 2020-03-03 23:18:47 -05:00
445d4b7e59 Update the documents of the custom mutator
- Merge python_mutators.md into custom_mutator.md
- Remove python_mutators.md
2020-03-03 23:17:24 -05:00
05a3418f86 added __afl_final_loc to all compile RTs 2020-03-04 01:51:41 +01:00
df46521658 Finish refactoring APIs for the custom mutator and Python module
- Remove AFL_PYTHON_ONLY (env) and python_only (variable)
- Unify fuzz API of the custom mutator and Python module
- Merge the custom mutator into the old python_stage, which is now renamed to custom_mutator_stage
2020-03-03 19:48:13 -05:00
d559d5a374 fix prev commit 2020-03-03 11:15:07 +01:00
469b8ee022 Merge branch 'master' of github.com:vanhauser-thc/AFLplusplus 2020-03-03 11:07:49 +01:00
385f7da77f allow custom cflags on llvm makefile 2020-03-03 11:07:41 +01:00
90506479e7 Refactoring fuzz_py API 2020-03-02 21:30:10 -05:00
b2a2b0fc21 Add initialization funcation wrapper for Python mutator 2020-03-02 19:30:05 -05:00
7862416844 Uniform API for both Python and custom mutator 2020-03-02 19:29:41 -05:00
031946136b Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-03-02 15:27:31 -05:00
7b59e05600 Add new APIs for the custom mutator 2020-03-02 15:27:29 -05:00
f6050ab804 Silenced output of if python not found 2020-03-02 16:12:12 +01:00
43e97a5aa2 Autoresume added to help 2020-03-02 16:10:08 +01:00
f0cf9c2cdf make afl-showmap quiet when called from afl-cmin* 2020-03-01 22:30:38 +01:00
3e0a3ec45f migrated autoresume to use get_afl_env 2020-03-01 14:09:21 +01:00
6865cd8d69 Added AFL_AUTORESUME option 2020-03-01 13:47:33 +01:00
59b80cb01e fix #218 for GCC plugin 2020-03-01 11:51:15 +01:00
d946be29b9 fix #218 2020-03-01 11:16:43 +01:00
95322c11d9 print OKF if an environment variable is successfully loaded - feebdack to this please ... 2020-02-29 20:49:16 +01:00
76ca6adbc5 afl-clang-fast: only show the official env vars 2020-02-29 15:12:27 +01:00
45aa579f68 Added missing dependency to the docu (#216)
* Added missing dependency to the documentation. Tested on Debian 10

* Added documentation for Debian users

Co-authored-by: adamgrimm99 <55899195+adamgrimm99@users.noreply.github.com>
2020-02-29 14:42:19 +01:00
9ddd7e0e3f wget is no longer necessary for unicornafl which is cloned now. (#217) 2020-02-29 14:39:29 +01:00
6730b6a15a code-format, env.md fixes and adding -hh for env usage display into afl-fuzz and Makefile 2020-02-29 14:23:44 +01:00
6e08be1d0b add env info to afl-fuzz (please review!), small clarifications in docs/env_variables.md 2020-02-28 22:02:55 +01:00
0b21441590 add env info to afl-gcc-fast 2020-02-28 19:50:07 +01:00
449a14d1d0 more examples for README and custom_mutator README 2020-02-28 14:07:38 +01:00
57495a794d updated contribution info 2020-02-28 10:23:23 +01:00
7d0ae2939d update todo 2020-02-28 07:07:27 +01:00
7fa289316a fix for qemu_mode where capstone 4.0+ is installed 2020-02-28 06:50:15 +01:00
0e8388d3ea add env info to afl-clang-fast, small Android change 2020-02-28 05:00:22 +01:00
caa8fea8e2 add env info to afl-showmap, in qemu_mode add forgotten MacOSX env var to afl-analyze, afl-fuzz, afl-tmin 2020-02-28 03:31:50 +01:00
212e5d1a72 v2.62d 2020-02-28 01:16:36 +01:00
713952b9c7 v2.62c 2020-02-28 01:13:28 +01:00
20b8fc075b v2.62c 2020-02-28 01:12:44 +01:00
fc77f0bb96 i am too tired :-( 2020-02-28 01:02:21 +01:00
2eb7d0d88c update ideas 2020-02-28 00:55:44 +01:00
41493b1e3f cmplog_shm shmat was missing result check 2020-02-28 00:41:56 +01:00
f526bb2ecb better alloc-inl.h 2020-02-28 00:35:59 +01:00
4e37e12c06 code-format 2020-02-28 00:19:36 +01:00
d83ab141f6 cpyright 2020-02-27 23:22:29 +01:00
11236dd545 restore alloc-inl from AFL 2020-02-27 21:11:45 +01:00
bf8a154bec perf-fuzz idea 2020-02-27 20:58:30 +01:00
2b9ecd6eec Merge branch 'master' of github.com:vanhauser-thc/AFLplusplus 2020-02-27 16:04:20 +01:00
3712a70115 bye bye SanCov for CmpLog 2020-02-27 16:04:07 +01:00
e4f01a6825 Merge pull request #213 from Kusoku/master
Fix hanging fork and child with -V -E
2020-02-27 10:52:57 +01:00
3549cbb3a2 Fix hanging fork and child with -V -E
If we let multiple fuzzers end with -V or -E option, it will cause it to think we are still occupying the cores, even if they are free, once we try to run another job it would return an error that no free nodes are available.

This change fixes that problem.
2020-02-27 00:09:26 +01:00
7c17697cae catch if shmat fails 2020-02-26 22:35:09 +01:00
0e1d306b2e beautifying man pages 2020-02-25 21:58:17 +01:00
70c208ead7 Merge branch 'master' of https://github.com/vanhauser-thc/AFLplusplus 2020-02-25 21:42:30 +01:00
2d25662b81 man page tuning 2020-02-25 21:41:31 +01:00
e12edca29a Merge branch 'master' of github.com:vanhauser-thc/AFLplusplus 2020-02-25 21:24:43 +01:00
7e0663e4e0 fix #212 2020-02-25 21:24:31 +01:00
4bd736e1a7 more env info for afl-plot and afl-analyze 2020-02-25 20:54:08 +01:00
d39830a4dc portability: replace GNU extension of date (-I) with posix "+%y-%m-%d" 2020-02-25 20:31:08 +01:00
d7c9f947ed disable arm64 travis because they are buggy 2020-02-25 17:49:39 +01:00
84426631b4 update docker info 2020-02-25 16:30:22 +01:00
2c9c2e139e afl-gcc change -> test.sh 2020-02-25 14:01:55 +01:00
a540bae7a9 left over README reference fix 2020-02-25 08:43:49 +01:00
891b568678 fix references to README docs 2020-02-25 08:34:44 +01:00
901360b902 sync afl-as setup with afl-llvm-rt (add __afl_area_ptr[0] = 1) 2020-02-24 23:19:56 +01:00
c8295e1485 add env info to afl-tmin 2020-02-24 22:23:51 +01:00
9cc8ebd351 2.61d init 2020-02-24 17:26:02 +01:00
165 changed files with 15653 additions and 7957 deletions

View File

@ -52,7 +52,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true

11
.gitignore vendored
View File

@ -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,12 @@ 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

View File

@ -5,6 +5,7 @@ sudo: required
branches:
only:
- master
- dev
matrix:
include:
@ -17,10 +18,10 @@ matrix:
- os: linux
dist: trusty
env: NAME="trusty-amd64" MODERN="no" GCC="4.8"
- os: linux
dist: xenial
arch: arm64
env: NAME="xenial-arm64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0" AFL_NO_X86="1" CPU_TARGET="aarch64"
# - os: linux # until travis can fix this!
# dist: xenial
# arch: arm64
# env: NAME="xenial-arm64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0" AFL_NO_X86="1" CPU_TARGET="aarch64"
# - os: osx
# osx_image: xcode11.2
# env: NAME="osx" HOMEBREW_NO_ANALYTICS="1" LINK="http://releases.llvm.org/9.0.0/" NAME="clang+llvm-9.0.0-x86_64-darwin-apple"
@ -28,6 +29,7 @@ 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
@ -39,8 +41,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 libtool libtool-bin automake bison libglib2.0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev ; 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 libcmocka-dev ; fi
script:
- gcc -v
@ -50,4 +52,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

View File

@ -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.

View File

@ -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

482
GNUmakefile Normal file
View File

@ -0,0 +1,482 @@
#
# 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
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/ -Werror -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
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. 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 --ldflags)
else
PYTHON_LIB ?= $(shell python3m-config --ldflags)
endif
endif
endif
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
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
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 STATIC
$(info Compiling static version of binaries)
# Disable python for static compilation to simplify things
PYTHON_OK=0
PYFLAGS=
CFLAGS += -static
LDFLAGS += -lm -lpthread -lz -lutil
endif
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_LDFLAGS+=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ifdef ASAN_BUILD
$(info Compiling ASAN version of binaries)
CFLAGS+=$(ASAN_CFLAGS)
LDFLAGS+=$(ASAN_LDFLAGS)
endif
ifdef PROFILING
$(info Compiling profiling version of binaries)
CFLAGS+=-pg
LDFLAGS+=-pg
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
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 "unit: perform unit tests (based on cmocka)"
@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 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 src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) 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
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean
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
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
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 ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable
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 >> $@
@./$* -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
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)

449
Makefile
View File

@ -1,447 +1,2 @@
#
# 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
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)" -I 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" -I 2>/dev/null || date -u -I)
else
BUILD_DATE ?= $(shell date -I)
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)
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
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 )
./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!"
else
test_build: afl-gcc afl-as afl-showmap
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
endif
all_done: test_build
@if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
.NOTPARALLEL: 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)
all:
@echo please use GNU make, thanks!

165
README.md
View File

@ -2,25 +2,27 @@
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
![Travis State](https://api.travis-ci.com/vanhauser-thc/AFLplusplus.svg?branch=master)
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master)
Release Version: 2.61c
Release Version: [2.63c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 2.61d
Github Version: 2.63d
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>,
Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
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
@ -42,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)
* Unicron 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
@ -52,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 >= 9 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>.
@ -88,13 +102,25 @@
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
@ -102,13 +128,16 @@ something cool
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 automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools
$ make distrib
$ sudo make install
```
@ -133,6 +162,7 @@ These build targets exist:
* 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
* 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
@ -146,7 +176,9 @@ These build options exist:
* STATIC - compile AFL++ static
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
* PROFILING - compile with profiling information (gprof)
* 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
@ -156,11 +188,12 @@ 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
$ cd AFLplusplus
$ 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
@ -175,9 +208,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
@ -187,7 +220,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
@ -198,7 +231,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,
@ -226,10 +259,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.
@ -265,7 +298,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:
@ -282,7 +315,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
@ -298,7 +331,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.
@ -310,18 +343,22 @@ 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)
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
@ -335,21 +372,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
@ -370,7 +410,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
@ -407,18 +447,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
@ -443,7 +483,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
@ -467,7 +507,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.
@ -478,7 +518,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
@ -507,13 +547,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.
@ -525,7 +565,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.
@ -560,12 +600,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,
@ -584,10 +623,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
@ -613,14 +652,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
@ -653,7 +692,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:
@ -701,16 +740,16 @@ without feedback, bug reports, or patches from:
Nathan Voss Dominik Maier
Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu
Josephine Calliotte
Josephine Calliotte Konrad Welc
```
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

88
TODO.md
View File

@ -1,92 +1,48 @@
# TODO list for AFL++
## Roadmap 2.61
## Roadmap 2.63
Makefile:
- -march=native -Ofast -flto=full (especially for afl-fuzz)
- complete custom_mutator API changes and documentation
- fix stability calculation bug
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.64
- context sensitive branch coverage in llvm_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?
- laf-intel build auto-dictionary?
## 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
- setting min_len/max_len/start_offset/end_offset limits for mutation output
llvm_mode:
- added context sensitive branch coverage
- add CT cov and ngram cov to LTO and InsTrim
- 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 :( )
- non colliding instrumentation
- 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?)
- 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

View File

@ -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
@ -94,15 +96,13 @@ function getopt(argc, argv, options, thisopt, i)
function usage() {
print \
"Usage: afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
"afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
"\n" \
"Required parameters:\n" \
"\n" \
" -i dir - input directory with starting corpus\n" \
" -o dir - output directory for minimized files\n" \
"\n" \
"Execution control settings:\n" \
"\n" \
" -f file - location read by the fuzzed program (stdin)\n" \
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
" -t msec - run time limit for child process (none)\n" \
@ -116,11 +116,10 @@ function usage() {
"For additional tips, please consult docs/README.md\n" \
"\n" \
"Environment variables used:\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
"AFL_PATH: path for the afl-showmap binary\n" \
"AFL_SKIP_BIN_CHECK: skip check for target binary\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
> "/dev/stderr"
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n"
exit 1
}
@ -265,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
@ -314,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"
@ -399,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
}
#######################################################

View File

@ -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
@ -126,7 +128,7 @@ Minimization settings:
-C - keep crashing inputs, reject everything else
-e - solve for edge coverage only, ignore hit counts
For additional tips, please consult docs/README.
For additional tips, please consult docs/README.md.
Environment variables used:
AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory

View File

@ -32,6 +32,8 @@ an empty directory where this tool can write the resulting plots to.
The program will put index.html and three PNG images in the output directory;
you should be able to view it with any web browser of your choice.
Environment variables used:
AFL_ALLOW_TMP: allow /var/tmp or /tmp for input and output directories
_EOF_
exit 1
@ -66,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

View File

@ -18,12 +18,13 @@
# instances of afl-fuzz.
#
echo "status check tool for afl-fuzz by Michal Zalewski"
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
echo
test "$1" = "-h" && {
echo $0
echo $0 [-s] output_directory
echo
echo afl-whatsup has no command line options
echo Options:
echo -s - skip details and output summary results only
echo
exit 1
}
@ -60,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
@ -74,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"
@ -82,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"
@ -91,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
@ -124,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
@ -140,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"
@ -156,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
@ -166,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

View File

@ -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"

View File

@ -1,7 +1,7 @@
# Changelog
This is the list of all noteworthy changes made in every public release of
the tool. See README for the general instruction manual.
the tool. See README.md for the general instruction manual.
## Staying informed
@ -9,6 +9,69 @@ 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.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 -
note that this mode is amazing, but quite some targets won't compile
- 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
not identifying crashes - UPDATE!
- Small fix for -E/-V to release the CPU
- CmpLog does not need sancov anymore
### Version ++2.61c (release):
- use -march=native if available
@ -40,7 +103,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- now does not need to be recompiled between trace-pc and pass
instrumentation. compile normally and set AFL_LLVM_USE_TRACE_PC :)
- LLVM 11 is supported
- CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog)
- CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog.md)
- afl-gcc, afl-clang-fast, afl-gcc-fast:
- experimental support for undefined behaviour sanitizer UBSAN
(set AFL_USE_UBSAN=1)
@ -152,7 +215,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.
@ -184,7 +247,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- fix llvm_mode AFL_TRACE_PC with modern llvm
- fix a crash in qemu_mode which also exists in stock afl
- added libcompcov, a laf-intel implementation for qemu! :)
see qemu_mode/libcompcov/README.libcompcov
see qemu_mode/libcompcov/README.libcompcov.md
- afl-fuzz now displays the selected core in the status screen (blue {#})
- updated afl-fuzz and afl-system-config for new scaling governor location
in modern kernels
@ -193,8 +256,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- if llvm_mode was compiled, afl-clang/afl-clang++ will point to these
instead of afl-gcc
- added instrim, a much faster llvm_mode instrumentation at the cost of
path discovery. See llvm_mode/README.instrim (https://github.com/csienslab/instrim)
- added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt
path discovery. See llvm_mode/README.instrim.md (https://github.com/csienslab/instrim)
- added MOpt (github.com/puppet-meteor/MOpt-AFL) mode, see docs/README.MOpt.md
- added code to make it more portable to other platforms than Intel Linux
- added never zero counters for afl-gcc and optionally (because of an
optimization issue in llvm < 9) for llvm_mode (AFL_LLVM_NEVER_ZERO=1)
@ -224,11 +287,11 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
LLVM and Qemu modes are now faster.
Important changes:
afl-fuzz: -e EXTENSION commandline option
llvm_mode: LAF-intel performance (needs activation, see llvm/README.laf-intel)
a few new environment variables for afl-fuzz, llvm and qemu, see docs/env_variables.txt
llvm_mode: LAF-intel performance (needs activation, see llvm/README.laf-intel.md)
a few new environment variables for afl-fuzz, llvm and qemu, see docs/env_variables.md
- Added the power schedules of AFLfast by Marcel Boehme, but set the default
to the AFL schedule, not to the FAST schedule. So nothing changes unless
you use the new -p option :-) - see docs/power_schedules.txt
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
@ -471,7 +534,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- Added libtokencap, a simple feature to intercept strcmp / memcmp and
generate dictionary entries that can help extend coverage.
- Moved libdislocator to its own dir, added README.
- Moved libdislocator to its own dir, added README.md.
- The demo in examples/instrumented_cmp is no more.

View File

@ -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

View File

@ -27,7 +27,7 @@ how to hit the ground running:
4) Get a small but valid input file that makes sense to the program. When
fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described in
dictionaries/README.dictionaries, too.
dictionaries/README.md, too.
5) If the program reads from stdin, run 'afl-fuzz' like so:

View File

@ -1,6 +1,6 @@
# american fuzzy lop plus plus (afl++)
![Travis State](https://api.travis-ci.com/vanhauser-thc/AFLplusplus.svg?branch=master)
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master)
Release Version: 2.60c
@ -11,7 +11,7 @@
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>,
Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
@ -75,7 +75,7 @@
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>.
@ -675,7 +675,7 @@ 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)
[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

View File

@ -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

View File

@ -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/

239
docs/custom_mutators.md Normal file
View File

@ -0,0 +1,239 @@
# 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.
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_pre_save(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 pre_save(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 fuzzer should fuzz the current queue
entry or not
- `fuzz` (required):
This method performs custom mutations on a given input. It also accepts an
additional test case.
- `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%.
- `pre_save` (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
`pre_save` function. This function is then transforms 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.
### 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`).
`deinit` the last method to be called, deinitializing the state.
Omitting any of three 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
```
### Run
C/C++
```bash
export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.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)

View File

@ -2,7 +2,7 @@
This document discusses the environment variables used by American Fuzzy Lop++
to expose various exotic functions that may be (rarely) useful for power
users or for some types of custom fuzzing setups. See README for the general
users or for some types of custom fuzzing setups. See README.md for the general
instruction manual.
## 1) Settings for afl-gcc, afl-clang, and afl-as - and gcc_plugin afl-gcc-fast
@ -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
@ -91,6 +93,76 @@ 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:
DEFAULT - classic AFL (map[cur_loc ^ prev_loc >> 1]++)
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)
Only one can be used.
### 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 9 or newer is used.
None of these 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_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.
- 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).
- Setting AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 will skip instrumenting
functions with a single basic block. This is useful for most C and
some C++ targets.
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
@ -115,19 +187,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
@ -198,6 +257,9 @@ checks or alter some of the more exotic semantics of the tool:
- 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.
@ -223,14 +285,15 @@ checks or alter some of the more exotic semantics of the tool:
for more.
- 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 +325,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:
@ -408,3 +481,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.

View File

@ -1,6 +1,10 @@
# Ideas for afl++
In the following, we describe a variety of ideas that could be implemented for further AFL++ versions.
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
@ -19,6 +23,8 @@ common issues of the academic code.
We aim to develop a pluggable grammar mutator for afl++ that combines
various results.
Mentor: andreafioraldi
## Expand on the MOpt mutator
Work on the MOpt mutator that is already in AFL++.
@ -27,11 +33,27 @@ 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.
Mentor: vanhauser-thc or andreafioraldi
## perf-fuzz Linux Kernel Module
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)
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
First tests to use QEMU 4 for binary-only AFL++ showed that caching behavior
@ -42,6 +64,8 @@ This is the cause why, right now, we cannot switch to QEMU 4.2.
Understanding the current instrumentation and fixing the current caching
issues will be needed.
Mentor: andreafioraldi
## WASM Instrumentation
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
@ -51,24 +75,46 @@ This can either be done by inserting instrumentation directly into the
WASM AST, or by patching feedback into a WASM VMs of choice, similar to
the current Unicorn instrumentation.
Mentor: any
## Machine Learning
Something with machine learning, better than NEUZZ :-)
Either improve a single mutator thorugh learning of many different bugs (a bug class) or gather deep insights about a single target beforehand (CFG, DFG, VFG, ...?) and improve performance for a single target.
Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-)
Either improve a single mutator thorugh learning of many different bugs
(a bug class) or gather deep insights about a single target beforehand
(CFG, DFG, VFG, ...?) and improve performance for a single target.
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 :-)

View File

@ -62,7 +62,7 @@ Specify `AFL_HARDEN=1` in the environment to enable hardening flags.
## Bumping into problems with non-reproducible crashes?
It happens, but usually
isn't hard to diagnose. See section #7 in README for tips.
isn't hard to diagnose. See section #7 in README.md for tips.
## Fuzzing is not just about memory corruption issues in the codebase.
Add some

View File

@ -1,7 +1,7 @@
# Notes for using ASAN with afl-fuzz
This file discusses some of the caveats for fuzzing under ASAN, and suggests
a handful of alternatives. See README for the general instruction manual.
a handful of alternatives. See README.md for the general instruction manual.
## 1) Short version
@ -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

View File

@ -1,7 +1,7 @@
# Tips for parallel fuzzing
This document talks about synchronizing afl-fuzz jobs on a single machine
or across a fleet of systems. See README for the general instruction manual.
or across a fleet of systems. See README.md for the general instruction manual.
## 1) Introduction

View File

@ -1,7 +1,7 @@
## Tips for performance optimization
This file provides tips for troubleshooting slow or wasteful fuzzing jobs.
See README for the general instruction manual.
See README.md for the general instruction manual.
## 1. Keep your test cases small

View File

@ -19,6 +19,8 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ
| `-p quad` | ![QUAD](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%5E2%7D%7Bf%28i%29%7D%2CM%5Cright%29) |
| `-p lin` | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%7D%7Bf%28i%29%7D%2CM%5Cright%29) |
| `-p exploit` (AFL) | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Calpha%28i%29) |
| `-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/).

View File

@ -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.

View File

@ -1,7 +1,7 @@
# Sister projects
This doc lists some of the projects that are inspired by, derived from,
designed for, or meant to integrate with AFL. See README for the general
designed for, or meant to integrate with AFL. See README.md for the general
instruction manual.
!!!
@ -252,7 +252,7 @@ https://code.google.com/p/address-sanitizer/wiki/AsanCoverage#Coverage_counters
### AFL JS (Han Choongwoo)
One-off optimizations to speed up the fuzzing of JavaScriptCore (now likely
superseded by LLVM deferred forkserver init - see llvm_mode/README.llvm).
superseded by LLVM deferred forkserver init - see llvm_mode/README.md).
https://github.com/tunz/afl-fuzz-js

View File

@ -1,7 +1,7 @@
# Understanding the status screen
This document provides an overview of the status screen - plus tips for
troubleshooting any warnings and red text shown in the UI. See README for
troubleshooting any warnings and red text shown in the UI. See README.md for
the general instruction manual.
## A note about colors
@ -374,24 +374,38 @@ 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
- `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
- `stability - percentage of bitmap bytes that behave consistently
- `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
- `command_line` - full command line used for the fuzzing session
- `slowest_exec_ms`- real time of the slowest execution in seconds
- `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.

View File

@ -1,7 +1,7 @@
# Technical "whitepaper" for afl-fuzz
This document provides a quick overview of the guts of American Fuzzy Lop.
See README for the general instruction manual; and for a discussion of
See README.md for the general instruction manual; and for a discussion of
motivations and design goals behind AFL, see historical_notes.md.
## 0. Design statement
@ -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:

View File

@ -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).

View File

@ -20,19 +20,24 @@ 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 gcc; echo $$?)
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep 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

View 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

View File

@ -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)

View File

@ -0,0 +1,28 @@
# 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!
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.

View File

@ -7,6 +7,7 @@ from copy import deepcopy
from lxml import etree as ET
import random, re, io
###########################
# The XmlMutatorMin class #
###########################
@ -149,7 +150,7 @@ class XmlMutatorMin:
# 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?

View File

@ -19,16 +19,19 @@ import random
import os
import re
def randel(l):
if not l:
return None
return l[random.randint(0, len(l)-1)]
def randel_pop(l):
if not l:
return None
return l.pop(random.randint(0, len(l)-1))
def write_exc_example(data, exc):
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))

View 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

View File

@ -0,0 +1,375 @@
/*
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, pre_save);
} 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_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size,
uint8_t **out_buf) {
uint8_t *pre_save_buf = maybe_grow(BUF_PARAMS(data, pre_save), buf_size + 5);
if (!pre_save_buf) {
perror("custom mutator realloc failed.");
*out_buf = NULL;
return 0;
}
memcpy(pre_save_buf + 5, buf, buf_size);
pre_save_buf[0] = 'A';
pre_save_buf[1] = 'F';
pre_save_buf[2] = 'L';
pre_save_buf[3] = '+';
pre_save_buf[4] = '+';
*out_buf = pre_save_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->pre_save_buf);
free(data->havoc_buf);
free(data->data_buf);
free(data->fuzz_buf);
free(data->trim_buf);
free(data);
}

View File

@ -16,6 +16,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
import random
COMMANDS = [
b"GET",
b"PUT",
b"DEL",
]
def init(seed):
'''
Called once when AFLFuzz starts up. Used to seed our RNG.
@ -24,9 +32,13 @@ def init(seed):
@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.
@ -36,11 +48,16 @@ def fuzz(buf, add_buf):
@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
@ -101,3 +118,68 @@ def fuzz(buf, add_buf):
# # removed in the last step
#
# return next_index
#
# def pre_save(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

View File

@ -16,6 +16,7 @@ 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.
@ -25,9 +26,9 @@ def init(seed):
'''
# Seed our RNG
random.seed(seed)
return 0
def fuzz(buf, add_buf):
def fuzz(buf, add_buf, max_size):
'''
Called per fuzzing iteration.
@ -37,6 +38,10 @@ def fuzz(buf, add_buf):
@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
'''

View File

@ -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;
}

View File

@ -9,8 +9,8 @@ __seed__ = "RANDOM"
__log__ = False
__log_file__ = "wrapper.log"
# AFL functions
# AFL functions
def log(text):
"""
Logger
@ -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
@ -42,7 +43,8 @@ def init(seed):
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.
"""
@ -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,7 +73,7 @@ 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")
@ -84,7 +86,7 @@ def fuzz(buf, add_buf):
try:
__mutator__.mutate(max=5)
log("fuzz(): Input mutated")
except:
except Exception:
log("fuzz(): Can't mutate input => returning buf")
return buf
@ -92,7 +94,7 @@ def fuzz(buf, add_buf):
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)

View File

@ -3,6 +3,7 @@
--------------------------------------------------
Originally written by Michal Zalewski
Edited by Dominik Maier, 2020
Copyright 2015 Google Inc. All rights reserved.
@ -41,22 +42,23 @@
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').
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
and return the original `len`.
2) If you want to skip this test case altogether and have AFL generate a
new one, return NULL. Use this sparingly - it's faster than running
the target program with patently useless inputs, but still wastes CPU
time.
new one, return 0 or set `*out_buf = NULL`.
Use this sparingly - it's faster than running the target program
with patently useless inputs, but still wastes CPU time.
3) If you want to modify the test case, allocate an appropriately-sized
buffer, move the data into that buffer, make the necessary changes, and
then return the new pointer. You can update *len if necessary, too.
then return the new pointer as out_buf. Return an appropriate len
afterwards.
Note that the buffer will *not* be freed for you. To avoid memory leaks,
you need to free it or reuse it on subsequent calls (as shown below).
*** DO NOT MODIFY THE ORIGINAL 'in_buf' BUFFER. ***
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
Aight. The example below shows a simple postprocessor that tries to make
sure that all input files start with "GIF89a".
@ -74,47 +76,84 @@
#define HEADER "GIF89a"
typedef struct post_state {
unsigned char *buf;
size_t size;
} post_state_t;
void *afl_postprocess_init(void *afl) {
post_state_t *state = malloc(sizeof(post_state_t));
if (!state) {
perror("malloc");
return NULL;
}
state->buf = calloc(sizeof(unsigned char), 4096);
if (!state->buf) { return NULL; }
return state;
}
/* The actual postprocessor routine called by afl-fuzz: */
const unsigned char* afl_postprocess(const unsigned char* in_buf,
unsigned int* len) {
static unsigned char* saved_buf;
unsigned char* new_buf;
size_t afl_postprocess(post_state_t *data, unsigned char *in_buf,
unsigned int len, unsigned char **out_buf) {
/* Skip execution altogether for buffers shorter than 6 bytes (just to
show how it's done). We can trust *len to be sane. */
show how it's done). We can trust len to be sane. */
if (*len < strlen(HEADER)) return NULL;
if (len < strlen(HEADER)) return 0;
/* Do nothing for buffers that already start with the expected header. */
if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf;
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
*out_buf = in_buf;
return len;
}
/* Allocate memory for new buffer, reusing previous allocation if
possible. */
new_buf = realloc(saved_buf, *len);
*out_buf = realloc(data->buf, len);
/* If we're out of memory, the most graceful thing to do is to return the
original buffer and give up on modifying it. Let AFL handle OOM on its
own later on. */
if (!new_buf) return in_buf;
saved_buf = new_buf;
if (!*out_buf) {
/* 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;
*out_buf = in_buf;
return len;
}
/* Copy the original data to the new location. */
memcpy(*out_buf, in_buf, len);
/* Insert the new header. */
memcpy(*out_buf, HEADER, strlen(HEADER));
/* Return the new len. It hasn't changed, so it's just len. */
return len;
}
/* Gets called afterwards */
void afl_postprocess_deinit(post_state_t *data) {
free(data->buf);
free(data);
}

View File

@ -5,6 +5,7 @@
Originally written by Michal Zalewski
Copyright 2015 Google Inc. All rights reserved.
Adapted to the new API, 2020 by Dominik Maier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -35,11 +36,32 @@
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
const unsigned char* afl_postprocess(const unsigned char* in_buf,
unsigned int* len) {
typedef struct post_state {
static unsigned char* saved_buf;
static unsigned int saved_len;
unsigned char *buf;
size_t size;
} post_state_t;
void *afl_postprocess_init(void *afl) {
post_state_t *state = malloc(sizeof(post_state_t));
if (!state) {
perror("malloc");
return NULL;
}
state->buf = calloc(sizeof(unsigned char), 4096);
if (!state->buf) { return NULL; }
return state;
}
size_t afl_postprocess(post_state_t *data, const unsigned char *in_buf,
unsigned int len, const unsigned char **out_buf) {
unsigned char *new_buf = (unsigned char *)in_buf;
unsigned int pos = 8;
@ -47,12 +69,17 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
/* Don't do anything if there's not enough room for the PNG header
(8 bytes). */
if (*len < 8) return in_buf;
if (len < 8) {
*out_buf = in_buf;
return len;
}
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
don't have that, we can bail out. */
while (pos + 12 <= *len) {
while (pos + 12 <= len) {
unsigned int chunk_len, real_cksum, file_cksum;
@ -62,7 +89,7 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
/* Bail out if chunk size is too big or goes past EOF. */
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > *len) break;
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
/* Chunk checksum is calculated for chunk ID (dword) and the actual
payload. */
@ -82,17 +109,23 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
if (new_buf == in_buf) {
if (*len <= saved_len) {
if (len <= data->size) {
new_buf = saved_buf;
new_buf = data->buf;
} else {
new_buf = realloc(saved_buf, UP4K(*len));
if (!new_buf) return in_buf;
saved_buf = new_buf;
saved_len = UP4K(*len);
memcpy(new_buf, in_buf, *len);
new_buf = realloc(data->buf, UP4K(len));
if (!new_buf) {
*out_buf = in_buf;
return len;
}
data->buf = new_buf;
data->size = UP4K(len);
memcpy(new_buf, in_buf, len);
}
@ -108,7 +141,16 @@ const unsigned char* afl_postprocess(const unsigned char* in_buf,
}
return new_buf;
*out_buf = new_buf;
return len;
}
/* Gets called afterwards */
void afl_postprocess_deinit(post_state_t *data) {
free(data->buf);
free(data);
}

View File

@ -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

View File

@ -38,12 +38,13 @@ enum {
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);
}

View File

@ -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]) {

View File

@ -18,18 +18,29 @@ 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 gcc; echo $$?)
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep 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

160
gcc_plugin/GNUmakefile Normal file
View 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

View File

@ -21,87 +21,105 @@
#
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
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-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"
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 +127,7 @@ all_done: test_build
.NOTPARALLEL: clean
vpath % ..
VPATH = ..
%.8: %
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ../$@
@echo .SH NAME >> ../$@
@ -123,13 +141,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

View File

@ -323,14 +323,30 @@ 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);
} else if (isatty(2) && !getenv("AFL_QUIET")) {
} else if ((isatty(2) && !getenv("AFL_QUIET")) ||
getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-gcc-fast" VERSION cRST
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n");
@ -344,7 +360,9 @@ int main(int argc, char** argv, char** envp) {
}
}
} else
be_quiet = 1;
check_environment_vars(envp);

View File

@ -52,8 +52,8 @@
#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
#endif
@ -533,7 +533,7 @@ int plugin_init(struct plugin_name_args * plugin_info,
}
/* Show a banner */
if (isatty(2) && !getenv("AFL_QUIET")) {
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(G_(cCYA "afl-gcc-pass" VERSION cRST
" initially by <aseipp@pobox.com>, maintainer: hexcoder-\n"));
@ -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) {

View File

@ -25,6 +25,9 @@
#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);
}
@ -214,7 +219,7 @@ static void __afl_start_forkserver(void) {
}
/* A simplified persistent mode handler, used as explained in README.llvm. */
/* A simplified persistent mode handler, used as explained in README.md. */
int __afl_persistent_loop(unsigned int max_cnt) {

View 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.
@ -261,6 +262,7 @@ static const u8* main_payload_32 =
" je __afl_setup_abort\n"
"\n"
#endif
" movb $1, (%eax)\n"
" /* Store the address of the SHM region. */\n"
"\n"
" movl %eax, __afl_area_ptr\n"
@ -383,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"
@ -563,6 +566,7 @@ static const u8* main_payload_64 =
" je __afl_setup_abort\n"
"\n"
#endif
" movb $1, (%rax)\n"
" /* Store the address of the SHM region. */\n"
"\n"
" movq %rax, %rdx\n"

File diff suppressed because it is too large Load Diff

142
include/afl-prealloc.h Normal file
View 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

View 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.
@ -34,6 +35,14 @@
#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
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
#define alloc_printf(_str...) \
@ -101,10 +110,13 @@ static inline void* DFL_ck_alloc(u32 size) {
}
/* Free memory */
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
is set, the old memory will be also clobbered with 0xFF. */
static inline void DFL_ck_free(void *mem) {
if (!mem) return;
free(mem);
}
@ -116,7 +128,6 @@ static inline void DFL_ck_free(void* mem) {
static inline void *DFL_ck_realloc(void *orig, u32 size) {
u8 *ret;
u32 old_size = 0;
if (!size) {
@ -127,10 +138,12 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
ALLOC_CHECK_SIZE(size);
ret = realloc(orig, size);
ALLOC_CHECK_RESULT(ret, size);
/* Catch pointer issues sooner: force relocation and make sure that the
original buffer is wiped. */
if (size > old_size) memset(ret + old_size, 0, size - old_size);
ret = realloc(orig, size);
ALLOC_CHECK_RESULT(ret, size);
return (void *)ret;
@ -141,8 +154,6 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
if (orig) size += ALLOC_BLK_INC;
return DFL_ck_realloc(orig, size);
}
@ -217,5 +228,638 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
#define alloc_report()
#else
// This is the original alloc-inl of stock afl
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
#define alloc_printf(_str...) \
({ \
\
u8 *_tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \
snprintf((char *)_tmp, _len + 1, _str); \
_tmp; \
\
})
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
#define ALLOC_CHECK_SIZE(_s) \
do { \
\
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0)
/* Macro to check malloc() failures and the like. */
#define ALLOC_CHECK_RESULT(_r, _s) \
do { \
\
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0)
/* Magic tokens used to mark used / freed chunks. */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
/* Positions of guard tokens in relation to the user-visible pointer. */
#define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
#define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
#define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
#define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
/* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256
/* Sanity-checking macros for pointers. */
#define CHECK_PTR(_p) \
do { \
\
if (_p) { \
\
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
\
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \
else \
ABORT("Corrupted head alloc canary."); \
\
} \
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
ABORT("Corrupted tail alloc canary."); \
\
} \
\
} while (0)
#define CHECK_PTR_EXPR(_p) \
({ \
\
typeof(_p) _tmp = (_p); \
CHECK_PTR(_tmp); \
_tmp; \
\
})
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */
static inline void *DFL_ck_alloc_nozero(u32 size) {
void *ret;
if (!size) return NULL;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return ret;
}
/* Allocate a buffer, returning zeroed memory. */
static inline void *DFL_ck_alloc(u32 size) {
void *mem;
if (!size) return NULL;
mem = DFL_ck_alloc_nozero(size);
return memset(mem, 0, size);
}
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
is set, the old memory will be also clobbered with 0xFF. */
static inline void DFL_ck_free(void *mem) {
if (!mem) return;
CHECK_PTR(mem);
#ifdef DEBUG_BUILD
/* Catch pointer issues sooner. */
memset(mem, 0xFF, ALLOC_S(mem));
#endif /* DEBUG_BUILD */
ALLOC_C1(mem) = ALLOC_MAGIC_F;
free(mem - ALLOC_OFF_HEAD);
}
/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
old memory is clobbered with 0xFF. */
static inline void *DFL_ck_realloc(void *orig, u32 size) {
void *ret;
u32 old_size = 0;
if (!size) {
DFL_ck_free(orig);
return NULL;
}
if (orig) {
CHECK_PTR(orig);
#ifndef DEBUG_BUILD
ALLOC_C1(orig) = ALLOC_MAGIC_F;
#endif /* !DEBUG_BUILD */
old_size = ALLOC_S(orig);
orig -= ALLOC_OFF_HEAD;
ALLOC_CHECK_SIZE(old_size);
}
ALLOC_CHECK_SIZE(size);
#ifndef DEBUG_BUILD
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
#else
/* Catch pointer issues sooner: force relocation and make sure that the
original buffer is wiped. */
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
if (orig) {
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
free(orig);
}
#endif /* ^!DEBUG_BUILD */
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
if (size > old_size) memset(ret + old_size, 0, size - old_size);
return ret;
}
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
repeated small reallocs without complicating the user code). */
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
#ifndef DEBUG_BUILD
if (orig) {
CHECK_PTR(orig);
if (ALLOC_S(orig) >= size) return orig;
size += ALLOC_BLK_INC;
}
#endif /* !DEBUG_BUILD */
return DFL_ck_realloc(orig, size);
}
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
static inline u8 *DFL_ck_strdup(u8 *str) {
void *ret;
u32 size;
if (!str) return NULL;
size = strlen((char *)str) + 1;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return memcpy(ret, str, size);
}
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
or NULL inputs. */
static inline void *DFL_ck_memdup(void *mem, u32 size) {
void *ret;
if (!mem || !size) return NULL;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return memcpy(ret, mem, size);
}
/* Create a buffer with a block of text, appending a NUL terminator at the end.
Returns NULL for zero-sized or NULL inputs. */
static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
u8 *ret;
if (!mem || !size) return NULL;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL + 1);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
memcpy(ret, mem, size);
ret[size] = 0;
return ret;
}
#ifndef DEBUG_BUILD
/* In non-debug mode, we just do straightforward aliasing of the above functions
to user-visible names such as ck_alloc(). */
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free
#define alloc_report()
#else
/* In debugging mode, we also track allocations to detect memory leaks, and the
flow goes through one more layer of indirection. */
/* Alloc tracking data structures: */
#define ALLOC_BUCKETS 4096
struct TRK_obj {
void *ptr;
char *file, *func;
u32 line;
};
#ifdef AFL_MAIN
struct TRK_obj *TRK[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS];
#define alloc_report() TRK_report()
#else
extern struct TRK_obj *TRK[ALLOC_BUCKETS];
extern u32 TRK_cnt[ALLOC_BUCKETS];
#define alloc_report()
#endif /* ^AFL_MAIN */
/* Bucket-assigning function for a given pointer: */
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
/* Add a new entry to the list of allocated objects. */
static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func,
u32 line) {
u32 i, bucket;
if (!ptr) return;
bucket = TRKH(ptr);
/* Find a free slot in the list of entries for that bucket. */
for (i = 0; i < TRK_cnt[bucket]; i++)
if (!TRK[bucket][i].ptr) {
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char *)file;
TRK[bucket][i].func = (char *)func;
TRK[bucket][i].line = line;
return;
}
/* No space available - allocate more. */
TRK[bucket] = DFL_ck_realloc_block(
TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char *)file;
TRK[bucket][i].func = (char *)func;
TRK[bucket][i].line = line;
TRK_cnt[bucket]++;
}
/* Remove entry from the list of allocated objects. */
static inline void TRK_free_buf(void *ptr, const char *file, const char *func,
u32 line) {
u32 i, bucket;
if (!ptr) return;
bucket = TRKH(ptr);
/* Find the element on the list... */
for (i = 0; i < TRK_cnt[bucket]; i++)
if (TRK[bucket][i].ptr == ptr) {
TRK[bucket][i].ptr = 0;
return;
}
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", func, file,
line);
}
/* Do a final report on all non-deallocated objects. */
static inline void TRK_report(void) {
u32 i, bucket;
fflush(0);
for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
for (i = 0; i < TRK_cnt[bucket]; i++)
if (TRK[bucket][i].ptr)
WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
}
/* Simple wrappers for non-debugging functions: */
static inline void *TRK_ck_alloc(u32 size, const char *file, const char *func,
u32 line) {
void *ret = DFL_ck_alloc(size);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file,
const char *func, u32 line) {
void *ret = DFL_ck_realloc(orig, size);
TRK_free_buf(orig, file, func, line);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_realloc_block(void *orig, u32 size, const char *file,
const char *func, u32 line) {
void *ret = DFL_ck_realloc_block(orig, size);
TRK_free_buf(orig, file, func, line);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func,
u32 line) {
void *ret = DFL_ck_strdup(str);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_memdup(void *mem, u32 size, const char *file,
const char *func, u32 line) {
void *ret = DFL_ck_memdup(mem, size);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void *TRK_ck_memdup_str(void *mem, u32 size, const char *file,
const char *func, u32 line) {
void *ret = DFL_ck_memdup_str(mem, size);
TRK_alloc_buf(ret, file, func, line);
return ret;
}
static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
u32 line) {
TRK_free_buf(ptr, file, func, line);
DFL_ck_free(ptr);
}
/* Aliasing user-facing names to tracking functions: */
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_alloc_nozero(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc(_p1, _p2) \
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc_block(_p1, _p2) \
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup(_p1, _p2) \
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup_str(_p1, _p2) \
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
#endif /* ^!DEBUG_BUILD */
#endif /* _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 */

5
include/android-ashmem.h Executable file → Normal file
View 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.

View File

@ -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.

View 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,14 +26,82 @@
#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);
#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** get_qemu_argv(u8* own_loc, char** argv, int argc);
char** get_wine_argv(u8* own_loc, char** argv, int argc);
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 */
/* 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.
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);
#endif

View 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.
@ -27,7 +28,7 @@
/* Version string: */
// c = release, d = volatile github dev, e = experimental branch
#define VERSION "++2.61c"
#define VERSION "++2.63c"
/******************************************************
* *
@ -40,6 +41,11 @@
#define USE_COLOR
/* If you want to have the original afl internal memory corruption checks.
Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */
//#define _WANT_ORIGINAL_AFL_ALLOC
/* 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

View 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.
@ -31,6 +32,10 @@
* Terminal colors *
*******************/
#ifndef MESSAGES_TO_STDOUT
#define MESSAGES_TO_STDOUT
#endif
#ifdef USE_COLOR
#define cBLK "\x1b[0;30m"

View File

@ -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[];

View File

@ -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,8 +28,48 @@
#ifndef __AFL_FORKSERVER_H
#define __AFL_FORKSERVER_H
void handle_timeout(int sig);
void init_forkserver(char **argv);
#include <stdio.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 */
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) */
u32 exec_tmout; /* Configurable exec timeout (ms) */
u64 mem_limit; /* Memory cap for child (MB) */
u8 *out_file, /* File to fuzz, if any */
*target_path; /* Path of the target */
FILE *plot_file; /* Gnuplot output file */
u8 child_timed_out; /* Traced process timed out? */
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
u32 prev_timed_out; /* if prev forkserver run timed out */
} afl_forkserver_t;
void afl_fsrv_init(afl_forkserver_t *fsrv);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv);
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
void afl_fsrv_killall();
#ifdef __APPLE__
#define MSG_FORK_ON_APPLE \

182
include/list.h Normal file
View 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];
u32 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

View File

@ -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,32 @@
#ifndef __AFL_SHAREDMEM_H
#define __AFL_SHAREDMEM_H
void setup_shm(unsigned char dumb_mode);
void remove_shm(void);
typedef struct sharedmem {
extern int cmplog_mode;
extern struct cmp_map* cmp_map;
// 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 size_alloc; /* actual allocated size */
size_t size_used; /* in use by shmem app */
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
View 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);
}

View 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.
@ -57,8 +58,22 @@ 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) \
@ -119,9 +134,13 @@ typedef int64_t s64;
#define likely(_x) (_x)
#define unlikely(_x) (_x)
#else
#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 */

View File

@ -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

View File

@ -1,6 +1,6 @@
# libdislocator, an abusive allocator
(See ../docs/README for the general instruction manual.)
(See ../docs/README.md for the general instruction manual.)
This is a companion library that can be used as a drop-in replacement for the
libc allocator in the fuzzed binaries. It improves the odds of bumping into

63
libtokencap/GNUmakefile Normal file
View File

@ -0,0 +1,63 @@
#
# american fuzzy lop++ - libtokencap
# --------------------------------
#
# Originally written by Michal Zalewski
#
# Copyright 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
#
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
override CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -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
all: $(TARGETS)
VPATH = ..
libtokencap.so: libtokencap.so.c ../config.h
$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
.NOTPARALLEL: clean
clean:
rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
rm -f ../libtokencap.so
install: all
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH)
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md

View File

@ -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

View File

@ -1,6 +1,6 @@
# strcmp() / memcmp() token capture library
(See ../docs/README for the general instruction manual.)
(See ../docs/README.md for the general instruction manual.)
This companion library allows you to instrument `strcmp()`, `memcmp()`,
and related functions to automatically extract syntax tokens passed to any of

366
llvm_mode/GNUmakefile Normal file
View File

@ -0,0 +1,366 @@
#
# 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 )
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)
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)
$(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
LLVM_LTO = 1
endif
ifeq "$(LLVM_NEW_API)" "1"
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
$(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
LLVM_STDCXX = c++14
LLVM_LTO = 1
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 9, afl-clang-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE)" "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++
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
# llvm-config --bindir may 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')
ifneq "$(CLANGVER)" "$(LLVMVER)"
CC = $(shell $(LLVM_CONFIG) --bindir)/clang
CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
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; }' | $(CC) -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; }' | $(CC) -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; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto
endif
endif
endif
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(AFL_REAL_LD)" ""
AFL_REAL_LD = $(shell readlink /bin/ld 2>/dev/null)
ifeq "$(AFL_REAL_LD)" ""
AFL_REAL_LD = $(shell readlink /usr/bin/ld 2>/dev/null)
endif
endif
endif
AFL_CLANG_FUSELD=
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -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_VERSION=\"$(LLVMVER)\" -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" -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` -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
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-clang-fast ../afl-ld ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.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)" "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)" "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)"
@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) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
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-ld: afl-ld.c
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
ln -sf afl-ld ../ld
@rm -f .test-instr
@-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -Wl,--afl -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto and afl-ld seem to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto"
@rm -f .test-instr
endif
endif
../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
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-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
endif
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc MarkNodes.cc
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
endif
# 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)
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 -a -f ../afl-ld ]; 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-ld $${DESTDIR}$(HELPER_PATH); ln -sf afl-ld $${DESTDIR}$(HELPER_PATH)/ld; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../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

View File

@ -54,6 +54,8 @@ struct InsTrim : public ModulePass {
protected:
std::list<std::string> myWhitelist;
uint32_t function_minimum_size = 1;
uint32_t debug = 0;
private:
std::mt19937 generator;
@ -131,7 +133,7 @@ struct InsTrim : public ModulePass {
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,10 +141,12 @@ struct InsTrim : public ModulePass {
be_quiet = 1;
if (getenv("AFL_DEBUG") != NULL) debug = 1;
#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
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
@ -152,6 +156,9 @@ struct InsTrim : public ModulePass {
}
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL)
function_minimum_size = 2;
// this is our default
MarkSetOpt = true;
@ -176,8 +183,19 @@ struct InsTrim : public ModulePass {
for (Function &F : M) {
// if it is external or only contains one basic block: skip it
if (F.size() < 2) { continue; }
if (debug) {
uint32_t bb_cnt = 0;
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 the function below our minimum size skip it (1 or 2)
if (F.size() < function_minimum_size) { continue; }
if (!myWhitelist.empty()) {
@ -383,62 +401,13 @@ struct InsTrim : public ModulePass {
}
// Bugfix #1: remove single block function instrumentation
if (function_minimum_size < 2) {
for (BasicBlock &BB : F) {
if (MarkSetOpt && MS.find(&BB) == MS.end()) {
// Bugfix #2: instrument blocks that should be but InsTrim
// doesn't due to an algorithmic bug
int more_than_one = -1;
for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); PI != E;
++PI) {
BasicBlock *Pred = *PI;
int count = 0;
if (more_than_one == -1) more_than_one = 0;
for (succ_iterator SI = succ_begin(Pred), E = succ_end(Pred);
SI != E; ++SI) {
BasicBlock *Succ = *SI;
if (Succ != NULL) count++;
}
if (count > 1) more_than_one = 1;
}
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) {
BasicBlock *Succ2 = *SI2;
if (Succ2 != NULL) cnt++;
}
if (cnt == 0) {
// fprintf(stderr, "INSERT!\n");
MS.insert(Succ);
total_rs += 1;
}
}
}
if (MS.find(&BB) == MS.end()) { continue; }
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev);
}
@ -450,9 +419,17 @@ struct InsTrim : public ModulePass {
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
auto PI = pred_begin(&BB);
auto PE = pred_end(&BB);
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
Value * L = NULL;
if (function_minimum_size < 2 && PI == PE) {
L = ConstantInt::get(Int32Ty, genLabel());
} 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) {
@ -466,6 +443,8 @@ struct InsTrim : public ModulePass {
L = PN;
}
/* Load prev_loc */
LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
@ -512,27 +491,36 @@ 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
// save the actually location ID to OldPrev if function_minimum_size > 1
if (function_minimum_size > 1) {
Value *Shr = IRB.CreateLShr(L, One32);
IRB.CreateStore(Shr, OldPrev)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
}
total_instr++;
}
}
if (!be_quiet) {
char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
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;
}

View File

@ -1,273 +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
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
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)
../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!

View File

@ -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}

88
llvm_mode/NOTES Normal file
View File

@ -0,0 +1,88 @@
markNodes
->
whitelist:
set meta information/context to functions? ask llvm-dev
setAttribute/hasAttribute?
afl-ld:
handle(=instrument) .a archives on the cmdline
afl-pass-lto-instrument.so:
either a or b:
a) use instrim
b) start in main() or _init() and first otherwise (warn!)
keep list of done functions
final: go through function list and instrument those missing
---------------------------
for (auto &module : Ctx.getModules()) {
auto &functionList = module->getModule()->getFunctionList();
for (auto &function : functionList) {
for (auto &bb : function) {
for (auto &instruction : bb) {
if (CallInst *callInst = dyn_cast<CallInst>(&instruction)) {
if (Function *calledFunction = callInst->getCalledFunction()) {
if (calledFunction->getName().startswith("llvm.dbg.declare")) {
for (auto &U : F.getUsers()) { <- unbekannt
if (auto CS = CallSite(U)) {
if (CS->getCalledFunction() == F)
getCalledValue()->stripPointerCasts()
-> for indirect calls
CallGraph(M)
#include "llvm/IR/CallSite.h"
unsigned int indirect_call_cnt = 0;
printf("Function: %s\n", F.getName().str().c_str());
int cnt=0;
for (auto *U : F.users()) {
// auto *I = dyn_cast<Instruction>(U);
// if (I) {
// if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) {
// printf("DIRECT CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str());
// }
printf("Callsite #%d\n", ++cnt);
CallSite CS(U);
auto *I = CS.getInstruction();
if (I) {
Value *called = CS.getCalledValue()->stripPointerCasts();
Function* f = dyn_cast<Function>(called);
if (f->getName().size() > 0) {
printf("test %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str());
if (f->getName() == F.getName()) {
printf("CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str());
}
} else
printf("FOO %s->...->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), F.getName().str().c_str());
if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) {
printf("DIRECT %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str());
}
} else {
printf("WE MISSED SOMETHING HERE!!\n");
indirect_call_cnt++;
}
}
oder:
for (auto *U : F.users()) {
if (auto CS = CallSite(U->getUser())) {
if (CS->isCallee(&U)) {
// foo
}
}
}

22
llvm_mode/README.ctx.md Normal file
View 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.

View File

@ -5,13 +5,12 @@ InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing
## Introduction
InsTrim uses CFG and markers to instrument just what is necessary in the
binary in llvm_mode. It is about 20-25% faster but as a cost has a lower
path discovery.
binary in llvm_mode. It is about 10-15% faster without disadvantages.
## Usage
Set the environment variable `AFL_LLVM_INSTRIM=1` during compilation of
the target.
Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1`
during compilation of the target.
There is also an advanced mode which instruments loops in a way so that
afl-fuzz can see which loop path has been selected but not being able to
@ -19,6 +18,15 @@ see how often the loop has been rerun.
This again is a tradeoff for speed for less path information.
To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`.
There is an additional optimization option that skips single block
functions. In 95% of the C targets and (guess) 50% of the C++ targets
it is good to enable this, as otherwise pointless instrumentation occurs.
The corner case where we want this instrumentation is when vtable/call table
is used and the index to that vtable/call table is not set in specific
basic blocks.
To enable skipping these (most of the time) unnecessary instrumentations set
`AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1`
## Background
The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing]

262
llvm_mode/README.lto.md Normal file
View File

@ -0,0 +1,262 @@
# afl-clang-lto - collision free instrumentation at link time
## TLDR;
1. This compile mode is very frickle if it works it is amazing, if it fails
- well use afl-clang-fast
2. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
coverage than anything else that is out there in the AFL world
3. You can use it together with llvm_mode: laf-intel and whitelisting
features and can be combined with cmplog/Redqueen
4. It only works with llvm 9 (and likely 10+ but is not tested there yet)
## Introduction and problem description
A big issue with how afl/afl++ works is that the basic block IDs that are
set during compilation are random - and hence natually the larger the number
of instrumented locations, the higher the number of edge collisions in the
map. This can result in not discovering new paths and therefore degrade the
efficiency of the fuzzing.
*This issue is understimated in the fuzzing community!*
With a 2^16 = 64kb standard map at already 256 instrumented blocks there is
on average one collision. On average a target has 10.000 to 50.000
instrumented blocks hence the real collisions are between 750-18.000!
To get to a solution that prevents any collision took several approaches
and many dead ends until we got to this:
* We instrument at link time when we have all files pre-compiled
* To instrument at link time we compile in LTO (link time optimization) mode
* Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the
correct LTO options and runs our own afl-ld linker instead of the system
linker
* Our linker collects all LTO files to link and instruments them so that
we have non-colliding edge overage
* We use a new (for afl) edge coverage - which is the same as in llvm
-fsanitize=coverage edge coverage mode :)
* after inserting our instrumentation in all interesting edges we link
all parts of the program together to our executable
The result:
* 10-15% speed gain compared to llvm_mode
* guaranteed non-colliding edge coverage :-)
* The compile time especially for libraries can be longer
Example build output from a libtiff build:
```
/bin/bash ../libtool --tag=CC --mode=link afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm
libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm
afl-clang-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
afl-ld++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de> (level 0)
[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir
[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir
[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll
[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc
[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc
afl-llvm-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
[+] Running real linker /bin/x86_64-linux-gnu-ld
[+] Linker was successful
```
## How to use afl-clang-lto
Just use afl-clang-lto like you did afl-clang-fast or afl-gcc.
Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and
laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
Instrim does not - but we can not really use it anyway for our approach.
Example:
```
CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
make
```
## Potential issues
### compiling libraries fails
If you see this message:
```
/bin/ld: libfoo.a: error adding symbols: archive has no index; run ranlib to add one
```
This is because usually gnu gcc ranlib is being called which cannot deal with clang LTO files.
The solution is simple: when you ./configure you have also have to set RANLIB=llvm-ranlib and AR=llvm-ar
Solution:
```
AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared
```
and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ...
### "linking globals named '...': symbol multiply defined" error
The target program is using multiple global variables or functions with the
same name. This is a common error when compiling a project with LTO, and
the fix is `-Wl,--allow-multiple-definition` - however llvm-link which we
need to link all llvm IR LTO files does not support this - yet (hopefully).
Hence if you see this error either you have to remove the duplicate global
variable (think `#ifdef` ...) or you are out of luck. :-(
### "expected top-level entity" + binary ouput error
This happens if multiple .a archives are to be linked and they contain the
same object filenames, the first in LTO form, the other in ELF form.
This can not be fixed programmatically, but can be fixed by hand.
You can try to delete the file from either archive
(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
and instrumentation by hand (see below).
### "undefined reference to ..."
This *can* be the opposite situation of the "expected top-level entity" error -
the library with the ELF file is before the LTO library.
However it can also be a bug in the program - try to compile it normally. If
fails then it is a bug in the program.
Solutions: You can try to delete the file from either archive, e.g.
(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
and instrumentation by hand (see below).
### "File format not recognized"
This happens if the build system has fixed LDFLAGS, CPPFLAGS, CXXFLAGS and/or
CFLAGS. Ensure that they all contain the `-flto` flag that afl-clang-lto was
compiled with (you can see that by typing `afl-clang-lto -h` and inspecting
the last line of the help output) and add them otherwise
### clang is hardcoded to /bin/ld
Some clang packages have 'ld' hardcoded to /bin/ld. This is an issue as this
prevents "our" afl-ld being called.
-fuse-ld=/path/to/afl-ld should be set through makefile magic in llvm_mode -
if it is supported - however if this fails you can try:
```
LDFLAGS=-fuse-ld=</path/to/afl-ld
```
As workaround attempt #2 you will have to switch /bin/ld:
```
mv /bin/ld /bin/ld.orig
cp afl-ld /bin/ld
```
This can result in two problems though:
!1!
When compiling afl-ld, the build process looks at where the /bin/ld link
is going to. So when the workaround was applied and a recompiling afl-ld
is performed then the link is gone and the new afl-ld clueless where
the real ld is.
In this case set AFL_REAL_LD=/bin/ld.orig
!2!
When you install an updated gcc/clang/... package, your OS might restore
the ld link.
### Performing the steps by hand
It is possible to perform all the steps afl-ld by hand to workaround issues
in the target.
1. Recompile with AFL_DEBUG=1 and collect the afl-clang-lto command that fails
e.g.: `AFL_DEBUG=1 make 2>&1 | grep afl-clang-lto | tail -n 1`
2. run this command prepended with AFL_DEBUG=1 and collect the afl-ld command
parameters, e.g. `AFL_DEBUG=1 afl-clang-lto[++] .... | grep /afl/ld`
3. for every .a archive you want to instrument unpack it into a seperate
directory, e.g.
`mkdir archive1.dir ; cd archive1.dir ; llvm-link x ../<archive>.a`
4. run `file archive*.dir/*.o` and make two lists, one containing all ELF files
and one containing all LLVM IR bitcode files.
You do the same for all .o files of the ../afl/ld command options
5. Create a single bitcode file by using llvm-link, e.g.
`llvm-link -o all-bitcode.bc <list of all LLVM IR .o files>`
If this fails it is game over - or you modify the source code
6. Run the optimizer on the new bitcode file:
`opt -O3 --polly -o all-optimized.bc all-bitcode.bc`
7. Instrument the optimized bitcode file:
`opt --load=$AFL_PATH/afl-llvm-lto-instrumentation.so --disable-opt --afl-lto all-optimized.bc -o all-instrumented.bc
8. If the parameter `--allow-multiple-definition` is not in the list, add it
as first command line option.
9. Link everything together.
a) You use the afl-ld command and instead of e.g. `/usr/local/lib/afl/ld`
you replace that with `ld`, the real linker.
b) Every .a archive you instrumented files from you remove the <archive>.a
or -l<archive> from the command
c) If you have entries in your ELF files list (see step 4), you put them to
the command line - but them in the same order!
d) put the all-instrumented.bc before the first library or .o file
e) run the command and hope it compiles, if it doesn't you have to analyze
what the issue is and fix that in the approriate step above.
Yes this is long and complicated. That is why there is afl-ld doing this and
that why this can easily fail and not all different ways how it *can* fail can
be implemented ...
### compiling programs still fail
afl-clang-lto is still work in progress.
Complex targets are still likely not to compile and this needs to be fixed.
Please report issues at:
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
Known issues:
* ffmpeg
* bogofilter
* libjpeg-turbo-1.3.1
## Upcoming Work
1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions
2. Modify the forkserver + afl-fuzz so that only the necessary map size is
loaded and used - and communicated to afl-fuzz too.
Result: faster fork in the target and faster map analysis in afl-fuzz
=> more speed :-)
## Tested and working targets
* libpng-1.2.53
* libxml2-2.9.2
* tiff-4.0.4
* unrar-nonfree-5.6.6
* exiv 0.27
* jpeg-6b
## History
This was originally envisioned by hexcoder- in Summer 2019, however we saw no
way to create a pass that is run at link time - although there is a option
for this in the PassManager: EP_FullLinkTimeOptimizationLast
("Fun" info - nobody knows what this is doing. And the developer who
implemented this didn't respond to emails.)
In December came then the idea to implement this as a pass that is run via
the llvm "opt" program, which is performed via an own linker that afterwards
calls the real linker.
This was first implemented in January and work ... kinda.
The LTO time instrumentation worked, however the "how" the basic blocks were
instrumented was a problem, as reducing duplicates turned out to be very,
very difficult with a program that has so many paths and therefore so many
dependencies. At lot of stratgies were implemented - and failed.
And then sat solvers were tried, but with over 10.000 variables that turned
out to be a dead-end too.
The final idea to solve this came from domenukk who proposed to insert a block
into an edge and then just use incremental counters ... and this worked!
After some trials and errors to implement this vanhauser-thc found out that
there is actually an llvm function for this: SplitEdge() :-)
Still more problems came up though as this only works without bugs from
llvm 9 onwards, and with high optimization the link optimization ruins
the instrumented control flow graph.
As long as there are no larger changes in llvm this all should work well now ...

View File

@ -2,7 +2,7 @@
(See [../README](../README.md) for the general instruction manual.)
(See [../gcc_plugin/README.gcc](../gcc_plugin/README.gcc.md) for the GCC-based instrumentation.)
(See [../gcc_plugin/README](../gcc_plugin/README.md) for the GCC-based instrumentation.)
## 1) Introduction
@ -92,13 +92,33 @@ which C/C++ files to actually instrument. See [README.whitelist](README.whitelis
For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md)
Then there is an optimized instrumentation strategy that uses CFGs and
markers to just instrument what is needed. This increases speed by 20-25%
however has a lower path discovery.
If you want to use this, set AFL_LLVM_INSTRIM=1
Then there are different ways of instrumenting the target:
1. There is an optimized instrumentation strategy that uses CFGs and
markers to just instrument what is needed. This increases speed by 10-15%
without any disadvantages
If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1
See [README.instrim](README.instrim.md)
A new instrumentation called CmpLog is also available as an alternative to
2. An even better instrumentation strategy uses LTO and link time
instrumentation. Note that not all targets can compile in this mode, however
if it works it is the best option you can use.
Simply use afl-clang-lto/afl-clang-lto++ to use this option.
See [README.lto](README.lto.md)
3. Alternativly you can choose a completely different coverage method:
3a. N-GRAM coverage - which combines the previous visited edges with the
current one. This explodes the map but on the other hand has proven to be
effective for fuzzing.
See [README.ngram](README.ngram.md)
3b. Context sensitive coverage - which combines the visited edges with an
individual caller ID (the function that called the current one)
[README.ctx](README.ctx.md)
Then - additionally to one of the instrumentation options above - there is
a very effective new instrumentation option called CmpLog as an alternative to
laf-intel that allow AFL++ to apply mutations similar to Redqueen.
See [README.cmplog](README.cmplog.md)
@ -109,12 +129,18 @@ is not optimal and was only fixed in llvm 9.
You can set this with AFL_LLVM_NOT_ZERO=1
See [README.neverzero](README.neverzero.md)
## 4) Gotchas, feedback, bugs
## 4) Snapshot feature
To speed up fuzzing you can use a linux loadable kernel module which enables
a snapshot feature.
See [README.snapshot](README.snapshot.md)
## 5) Gotchas, feedback, bugs
This is an early-stage mechanism, so field reports are welcome. You can send bug
reports to <afl-users@googlegroups.com>.
## 5) Bonus feature #1: deferred initialization
## 6) Bonus feature #1: deferred initialization
AFL tries to optimize performance by executing the targeted binary just once,
stopping it just before main(), and then cloning this "master" process to get
@ -162,7 +188,7 @@ will keep working normally when compiled with a tool other than afl-clang-fast.
Finally, recompile the program with afl-clang-fast (afl-gcc or afl-clang will
*not* generate a deferred-initialization binary) - and you should be all set!
## 6) Bonus feature #2: persistent mode
## 7) Bonus feature #2: persistent mode
Some libraries provide APIs that are stateless, or whose state can be reset in
between processing different input files. When such a reset is performed, a

28
llvm_mode/README.ngram.md Normal file
View File

@ -0,0 +1,28 @@
# AFL N-Gram Branch Coverage
## Source
This is an LLVM-based implementation of the n-gram branch coverage proposed in
the paper ["Be Sensitive and Collaborative: Analzying Impact of Coverage Metrics
in Greybox Fuzzing"](https://www.usenix.org/system/files/raid2019-wang-jinghan.pdf),
by Jinghan Wang, et. al.
Note that the original implementation (available
[here](https://github.com/bitsecurerlab/afl-sensitive))
is built on top of AFL's QEMU mode.
This is essentially a port that uses LLVM vectorized instructions to achieve
the same results when compiling source code.
In math the branch coverage is performed as follows:
`map[current_location ^ prev_location[0] >> 1 ^ prev_location[1] >> 1 ^ ... up to n-1`] += 1`
## Usage
The size of `n` (i.e., the number of branches to remember) is an option
that is specified either in the `AFL_LLVM_INSTRUMENT=NGRAM-{value}` or the
`AFL_LLVM_NGRAM_SIZE` environment variable.
Good values are 2, 4 or 8, valid are 2-16.
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.

View File

@ -0,0 +1,16 @@
# AFL++ snapshot feature
Snapshotting is a feature that makes a snapshot from a process and then
restores it's state, which is faster then forking it again.
All targets compiled with llvm_mode are automatically enabled for the
snapshot feature.
To use the snapshot feature for fuzzing compile and load this kernel
module: [https://github.com/AFLplusplus/AFL-Snapshot-LKM](https://github.com/AFLplusplus/AFL-Snapshot-LKM)
Note that is has little value for persistent (__AFL_LOOP) fuzzing.
## Notes
Snapshot does not work with multithreaded targets yet. Still in WIP, it is now usable only for single threaded applications.

10
llvm_mode/TODO Normal file
View File

@ -0,0 +1,10 @@
TODO for afl-ld:
* handle libfoo.a object archives
TODO for afl-llvm-lto-instrumentation:
* better algo for putting stuff in the map?
* try to predict how long the instrumentation process will take
TODO for afl-llvm-lto-whitelist
* different solution then renaming?

View File

@ -29,11 +29,13 @@
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "llvm-ngram-coverage.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <assert.h>
@ -41,9 +43,42 @@ 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 */
static u8 llvm_fullpath[PATH_MAX];
static u8 instrument_mode;
static u8 * lto_flag = AFL_CLANG_FLTO;
static u8 * march_opt = CFLAGS_OPT;
static u8 debug;
static u8 cwd[4096];
static u8 cmplog_mode;
u8 use_stdin = 0; /* dummy */
enum {
INSTRUMENT_CLASSIC = 0,
INSTRUMENT_AFL = 0,
INSTRUMENT_DEFAULT = 0,
INSTRUMENT_PCGUARD = 1,
INSTRUMENT_INSTRIM = 2,
INSTRUMENT_CFG = 2,
INSTRUMENT_LTO = 3,
INSTRUMENT_CTX = 4,
INSTRUMENT_NGRAM = 5 // + ngram value of 2-16 = 7 - 21
};
char instrument_mode_string[6][16] = {
"DEFAULT", "PCGUARD", "CFG", "LTO", "CTX",
};
u8 *getthecwd() {
static u8 fail[] = "";
if (getcwd(cwd, sizeof(cwd)) == NULL) return fail;
return cwd;
}
/* Try to find the runtime libraries. If that fails, abort. */
static void find_obj(u8 *argv0) {
@ -82,7 +117,7 @@ static void find_obj(u8* argv0) {
*slash = '/';
#ifdef __ANDROID__
tmp = alloc_printf("%s/afl-llvm-rt.so", afl_path);
tmp = alloc_printf("%s/afl-llvm-rt.so", dir);
#else
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
#endif
@ -114,16 +149,16 @@ static void find_obj(u8* argv0) {
}
FATAL(
"Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so.cc'. Please set "
"Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set "
"AFL_PATH");
}
/* 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, char **envp) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0;
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
u8 has_llvm_config = 0;
u8 *name;
@ -137,7 +172,13 @@ static void edit_params(u32 argc, char** argv) {
has_llvm_config = (strlen(LLVM_BINDIR) > 0);
if (!strcmp(name, "afl-clang-fast++")) {
if (instrument_mode == INSTRUMENT_LTO)
if (lto_flag[0] != '-')
FATAL(
"Using afl-clang-lto is not possible because Makefile magic did not "
"identify the correct -flto flag");
if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) {
u8 *alt_cxx = getenv("AFL_CXX");
if (has_llvm_config)
@ -199,31 +240,63 @@ static void edit_params(u32 argc, char** argv) {
// /laf
unsetenv("AFL_LD");
unsetenv("AFL_LD_CALLER");
if (cmplog_mode) {
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard,trace-cmp";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/cmplog-routines-pass.so", obj_path);
// reuse split switches from laf
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/split-switches-pass.so", obj_path);
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
cc_params[cc_par_cnt++] = "-fno-inline";
}
if (instrument_mode == INSTRUMENT_LTO) {
char *old_path = getenv("PATH");
char *new_path = alloc_printf("%s:%s", AFL_PATH, old_path);
setenv("PATH", new_path, 1);
setenv("AFL_LD", "1", 1);
if (getenv("AFL_LLVM_WHITELIST") != NULL) {
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-lto-whitelist.so", obj_path);
}
#ifdef AFL_CLANG_FUSELD
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s/afl-ld", AFL_PATH);
#endif
cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = AFL_PATH;
cc_params[cc_par_cnt++] = lto_flag;
} else {
#ifdef USE_TRACE_PC
cc_params[cc_par_cnt++] =
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
// cc_params[cc_par_cnt++] = "-mllvm";
// cc_params[cc_par_cnt++] =
// "-fsanitize-coverage=trace-cmp,trace-div,trace-gep";
// cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
#else
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
if (instrument_mode == INSTRUMENT_PCGUARD) {
cc_params[cc_par_cnt++] =
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
@ -233,7 +306,7 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
if (getenv("AFL_LLVM_INSTRIM") != NULL || getenv("INSTRIM_LIB") != NULL)
if (instrument_mode == INSTRUMENT_CFG)
cc_params[cc_par_cnt++] =
alloc_printf("%s/libLLVMInsTrim.so", obj_path);
else
@ -241,16 +314,12 @@ static void edit_params(u32 argc, char** argv) {
}
#endif /* ^USE_TRACE_PC */
}
cc_params[cc_par_cnt++] = "-Qunused-arguments";
/* Detect stray -v calls from ./configure scripts. */
if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;
while (--argc) {
u8 *cur = *(++argv);
@ -261,16 +330,11 @@ static void edit_params(u32 argc, char** argv) {
if (!strcmp(cur, "-x")) x_set = 1;
if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E"))
maybe_linking = 0;
if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (!strcmp(cur, "-shared")) maybe_linking = 0;
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
continue;
@ -320,20 +384,29 @@ static void edit_params(u32 argc, char** argv) {
}
#ifdef USE_TRACE_PC
if (getenv("AFL_USE_CFISAN")) {
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC"))
if (getenv("AFL_INST_RATIO"))
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
if (instrument_mode != INSTRUMENT_LTO) {
#endif /* USE_TRACE_PC */
uint32_t i = 0, found = 0;
while (envp[i] != NULL && !found)
if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
if (!found) cc_params[cc_par_cnt++] = "-flto";
}
cc_params[cc_par_cnt++] = "-fsanitize=cfi";
cc_params[cc_par_cnt++] = "-fvisibility=hidden";
}
if (!getenv("AFL_DONT_OPTIMIZE")) {
cc_params[cc_par_cnt++] = "-g";
cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops";
if (strlen(march_opt) > 1 && march_opt[0] == '-')
cc_params[cc_par_cnt++] = march_opt;
}
@ -406,8 +479,6 @@ static void edit_params(u32 argc, char** argv) {
#endif /* ^__APPLE__ */
"_I(); } while (0)";
if (maybe_linking) {
if (x_set) {
cc_params[cc_par_cnt++] = "-x";
@ -442,8 +513,6 @@ static void edit_params(u32 argc, char** argv) {
#endif
}
cc_params[cc_par_cnt] = NULL;
}
@ -452,25 +521,162 @@ static void edit_params(u32 argc, char** argv) {
int main(int argc, char **argv, char **envp) {
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
int i;
char *callname = "afl-clang-fast", *ptr;
if (getenv("AFL_DEBUG")) {
debug = 1;
if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
} else if (getenv("AFL_QUIET"))
be_quiet = 1;
#ifdef USE_TRACE_PC
printf(
cCYA
"afl-clang-fast" VERSION cRST
" [tpcg] by <lszekeres@google.com>\n"
#else
printf(
cCYA
"afl-clang-fast" VERSION cRST
" by <lszekeres@google.com>\n"
#endif /* ^USE_TRACE_PC */
instrument_mode = INSTRUMENT_PCGUARD;
#endif
if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) {
if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
strncasecmp(ptr, "instrim", strlen("instrim")) == 0)
instrument_mode = INSTRUMENT_CFG;
else if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0)
instrument_mode = INSTRUMENT_PCGUARD;
else if (strncasecmp(ptr, "lto", strlen("lto")) == 0)
instrument_mode = INSTRUMENT_LTO;
else if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) {
instrument_mode = INSTRUMENT_CTX;
setenv("AFL_LLVM_CTX", "1", 1);
} else if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) {
ptr += strlen("ngram");
while (*ptr && (*ptr < '0' || *ptr > '9'))
ptr++;
if (!*ptr)
if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL)
FATAL(
"you must set the NGRAM size with (e.g. for value 2) "
"AFL_LLVM_INSTRUMENT=ngram-2");
instrument_mode = INSTRUMENT_NGRAM + atoi(ptr);
if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
FATAL(
"NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
"(%u)",
NGRAM_SIZE_MAX);
ptr = alloc_printf("%u", instrument_mode - INSTRUMENT_NGRAM);
setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1);
} else if (strncasecmp(ptr, "classic", strlen("classic")) != 0 ||
strncasecmp(ptr, "default", strlen("default")) != 0 ||
strncasecmp(ptr, "afl", strlen("afl")) != 0)
FATAL("unknown AFL_LLVM_INSTRUMENT value: %s", ptr);
}
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
if (instrument_mode == 0)
instrument_mode = INSTRUMENT_PCGUARD;
else if (instrument_mode != INSTRUMENT_PCGUARD)
FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
}
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
getenv("INSTRIM_LIB")) {
if (instrument_mode == 0)
instrument_mode = INSTRUMENT_CFG;
else if (instrument_mode != INSTRUMENT_CFG)
FATAL(
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
}
if (getenv("AFL_LLVM_CTX")) {
if (instrument_mode == 0)
instrument_mode = INSTRUMENT_CTX;
else if (instrument_mode != INSTRUMENT_CTX)
FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_CTX together");
}
if (getenv("AFL_LLVM_NGRAM_SIZE")) {
if (instrument_mode == 0) {
instrument_mode = INSTRUMENT_NGRAM + atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
if (instrument_mode < INSTRUMENT_NGRAM + 2 ||
instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX)
FATAL(
"NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
"(%u)",
NGRAM_SIZE_MAX);
} else if (instrument_mode != INSTRUMENT_NGRAM)
FATAL(
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_NGRAM_SIZE "
"together");
}
if (instrument_mode < INSTRUMENT_NGRAM)
ptr = instrument_mode_string[instrument_mode];
else
ptr = alloc_printf("NGRAM-%u", instrument_mode - INSTRUMENT_NGRAM);
if (strstr(argv[0], "afl-clang-lto") != NULL) {
if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO) {
callname = "afl-clang-lto";
instrument_mode = INSTRUMENT_LTO;
ptr = instrument_mode_string[instrument_mode];
} else {
if (!be_quiet)
WARNF("afl-clang-lto called with mode %s, using that mode instead",
ptr);
}
}
#ifndef AFL_CLANG_FLTO
if (instrument_mode == INSTRUMENT_LTO)
FATAL("instrumentation mode LTO specified but LLVM support not available");
#endif
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
if (instrument_mode != INSTRUMENT_LTO)
printf("afl-clang-fast" VERSION " by <lszekeres@google.com> in %s mode\n",
ptr);
else
printf("afl-clang-lto" VERSION
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in %s mode\n",
ptr);
SAYF(
"\n"
"afl-clang-fast[++] [options]\n"
"%s[++] [options]\n"
"\n"
"This is a helper application for afl-fuzz. It serves as a drop-in "
"replacement\n"
"for clang, letting you recompile third-party code with the required "
"for clang, letting you recompile third-party code with the "
"required "
"runtime\n"
"instrumentation. A common use pattern would be one of the "
"following:\n\n"
@ -483,48 +689,120 @@ int main(int argc, char** argv, char** envp) {
"an LLVM pass and tends to offer improved performance with slow "
"programs.\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"
"afl-clang-fast was built for llvm %s with the llvm binary path of "
"\"%s\".\n\n",
BIN_PATH, BIN_PATH, LLVM_VERSION, LLVM_BINDIR);
"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-llvm-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_USE_CFISAN: activate control flow sanitizer\n"
"AFL_LLVM_WHITELIST: enable whitelisting (selective "
"instrumentation)\n"
"AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
"AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
"AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
"AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
"function calls\n"
" to cascaded comparisons\n"
"AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to "
"cascaded "
"comp.\n"
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n",
callname, BIN_PATH, BIN_PATH);
SAYF(
"\nafl-clang-fast specific environment variables:\n"
"AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
"AFL_LLVM_INSTRUMENT: set instrumentation mode: DEFAULT, CFG "
"(INSTRIM), LTO, CTX, NGRAM-2 ... NGRAM-16\n"
"You can also use the old environment variables:"
"AFL_LLVM_CTX: use context sensitive coverage\n"
"AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
"AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n"
"AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
"AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub "
"option to INSTRIM)\n");
#ifdef AFL_CLANG_FLTO
SAYF(
"\nafl-clang-lto specific environment variables:\n"
"AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
"bb\n"
"AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
"global var\n"
"AFL_REAL_LD: use this linker instead of the compiled in path\n"
"AFL_LD_PASSTHROUGH: do not perform instrumentation (for configure "
"scripts)\n"
"\nafl-clang-lto was built with linker target \"%s\" and LTO flags "
"\"%s\"\n"
"If anything fails - be sure to read README.lto.md!\n",
AFL_REAL_LD, AFL_CLANG_FLTO);
#endif
SAYF(
"\nafl-clang-fast was built for llvm %s with the llvm binary path "
"of \"%s\".\n",
LLVM_VERSION, LLVM_BINDIR);
SAYF("\n");
exit(1);
} else if ((isatty(2) && !getenv("AFL_QUIET")) ||
} else if ((isatty(2) && !be_quiet) ||
getenv("AFL_DEBUG") != NULL) {
#ifdef USE_TRACE_PC
if (instrument_mode != INSTRUMENT_LTO)
SAYF(cCYA "afl-clang-fast" VERSION cRST
" [tpcg] by <lszekeres@google.com>\n");
#warning \
"You do not need to specifically compile with USE_TRACE_PC anymore, setting the environment variable AFL_LLVM_USE_TRACE_PC is enough."
#else
SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n");
#endif /* ^USE_TRACE_PC */
" by <lszekeres@google.com> in %s mode\n",
ptr);
else
SAYF(cCYA "afl-clang-lto" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> in mode %s\n",
ptr);
}
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < argc; i++)
SAYF(" \"%s\"", argv[i]);
SAYF("\n");
}
check_environment_vars(envp);
cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG");
if (cmplog_mode) printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
if (!be_quiet && cmplog_mode)
printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
#ifndef __ANDROID__
find_obj(argv[0]);
#endif
edit_params(argc, argv);
edit_params(argc, argv, envp);
/*
int i = 0;
printf("EXEC:");
while (cc_params[i] != NULL)
printf(" %s", cc_params[i++]);
printf("\n");
*/
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < cc_par_cnt; i++)
SAYF(" \"%s\"", cc_params[i]);
SAYF("\n");
}
execvp(cc_params[0], (char **)cc_params);

839
llvm_mode/afl-ld.c Normal file
View File

@ -0,0 +1,839 @@
/*
american fuzzy lop++ - wrapper for GNU ld
-----------------------------------------
Written by Marc Heuse <mh@mh-sec.de> for afl++
Maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <domenukk@gmail.com>
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
The sole purpose of this wrapper is to preprocess clang LTO files before
linking by ld and perform the instrumentation on the whole program.
*/
#define AFL_MAIN
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <dirent.h>
#define MAX_PARAM_COUNT 4096
static u8 **ld_params, /* Parameters passed to the real 'ld' */
**link_params, /* Parameters passed to 'llvm-link' */
**opt_params, /* Parameters passed to 'opt' opt */
**inst_params; /* Parameters passed to 'opt' inst */
static u8 *input_file; /* Originally specified input file */
static u8 *final_file, /* Instrumented file for the real 'ld' */
*linked_file, /* file where we link all files */
*modified_file; /* file that was optimized before instr */
static u8 *afl_path = AFL_PATH;
static u8 *real_ld = AFL_REAL_LD;
static u8 cwd[4096];
static u8 *tmp_dir;
static u8 *ar_dir;
static u8 ar_dir_cnt;
static u8 *libdirs[254];
static u8 libdir_cnt;
static u8 be_quiet, /* Quiet mode (no stderr output) */
debug, /* AFL_DEBUG */
passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/
we_link, /* we have bc/ll -> link + optimize */
just_version; /* Just show version? */
static u32 ld_param_cnt = 1, /* Number of params to 'ld' */
link_param_cnt = 1, /* Number of params to 'llvm-link' */
opt_param_cnt = 1, /* Number of params to 'opt' opt */
inst_param_cnt = 1; /* Number of params to 'opt' instr */
/* This function wipes a directory - our AR unpack directory in this case */
static u8 wipe_directory(u8 *path) {
DIR * d;
struct dirent *d_ent;
d = opendir(path);
if (!d) return 0;
while ((d_ent = readdir(d))) {
if (strcmp(d_ent->d_name, ".") != 0 && strcmp(d_ent->d_name, "..") != 0) {
u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
if (unlink(fname)) PFATAL("Unable to delete '%s'", fname);
ck_free(fname);
}
}
closedir(d);
return !!rmdir(path);
}
/* remove temporary files on fatal errors */
static void at_exit_handler(void) {
if (!getenv("AFL_KEEP_ASSEMBLY")) {
if (linked_file) {
unlink(linked_file);
linked_file = NULL;
}
if (modified_file) {
unlink(modified_file);
modified_file = NULL;
}
if (final_file) {
unlink(final_file);
final_file = NULL;
}
if (ar_dir != NULL) {
wipe_directory(ar_dir);
ar_dir = NULL;
}
}
}
/* This function checks if the parameter is a) an existing file and b)
if it is a BC or LL file, if both are true it returns 1 and 0 otherwise */
int is_llvm_file(const char *file) {
int fd;
u8 buf[5];
if ((fd = open(file, O_RDONLY)) < 0) {
if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file);
return 0;
}
if (read(fd, buf, 4) != 4) return 0;
buf[sizeof(buf) - 1] = 0;
close(fd);
if (strncmp(buf, "; Mo", 4) == 0) return 1;
if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde)
return 1;
return 0;
}
/* Return the current working directory, not thread safe ;-) */
u8 *getthecwd() {
static u8 fail[] = "";
if (getcwd(cwd, sizeof(cwd)) == NULL) return fail;
return cwd;
}
/* Check if an ar extracted file is already in the parameter list */
int is_duplicate(u8 **params, u32 ld_param_cnt, u8 *ar_file) {
for (uint32_t i = 0; i < ld_param_cnt; i++)
if (params[i] != NULL)
if (strcmp(params[i], ar_file) == 0) return 1;
return 0;
}
/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
Note that the file name is always the last parameter passed by GCC,
so we exploit this property to keep the code "simple". */
static void edit_params(int argc, char **argv) {
u32 i, have_lto = 0, libdir_index;
u8 libdir_file[4096];
if (tmp_dir == NULL) {
tmp_dir = getenv("TMPDIR");
if (!tmp_dir) tmp_dir = getenv("TEMP");
if (!tmp_dir) tmp_dir = getenv("TMP");
if (!tmp_dir) tmp_dir = "/tmp";
}
linked_file =
alloc_printf("%s/.afl-%u-%u-1.ll", tmp_dir, getpid(), (u32)time(NULL));
modified_file =
alloc_printf("%s/.afl-%u-%u-2.bc", tmp_dir, getpid(), (u32)time(NULL));
final_file =
alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL));
ld_params = ck_alloc(4096 * sizeof(u8 *));
link_params = ck_alloc(4096 * sizeof(u8 *));
inst_params = ck_alloc(12 * sizeof(u8 *));
opt_params = ck_alloc(12 * sizeof(u8 *));
ld_params[0] = (u8 *)real_ld;
ld_params[ld_param_cnt++] = "--allow-multiple-definition";
link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link");
link_params[link_param_cnt++] = "-S"; // we create the linked file as .ll
link_params[link_param_cnt++] = "-o";
link_params[link_param_cnt++] = linked_file;
opt_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
if (getenv("AFL_DONT_OPTIMIZE") == NULL)
opt_params[opt_param_cnt++] = "-O3";
else
opt_params[opt_param_cnt++] = "-O0";
// opt_params[opt_param_cnt++] = "-S"; // only when debugging
opt_params[opt_param_cnt++] = linked_file; // input: .ll file
opt_params[opt_param_cnt++] = "-o";
opt_params[opt_param_cnt++] = modified_file; // output: .bc file
inst_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
inst_params[inst_param_cnt++] =
alloc_printf("--load=%s/afl-llvm-lto-instrumentation.so", afl_path);
// inst_params[inst_param_cnt++] = "-S"; // only when debugging
inst_params[inst_param_cnt++] = "--disable-opt";
inst_params[inst_param_cnt++] = "--afl-lto";
inst_params[inst_param_cnt++] = modified_file; // input: .bc file
inst_params[inst_param_cnt++] = "-o";
inst_params[inst_param_cnt++] = final_file; // output: .bc file
// first we must collect all library search paths
for (i = 1; i < argc; i++)
if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L')
libdirs[libdir_cnt++] = argv[i] + 2;
// then we inspect all options to the target linker
for (i = 1; i < argc; i++) {
if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT)
FATAL(
"Too many command line parameters because of unpacking .a archives, "
"this would need to be done by hand ... sorry! :-(");
if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1;
if (!strcmp(argv[i], "-version")) {
just_version = 1;
ld_params[1] = argv[i];
ld_params[2] = NULL;
final_file = input_file;
return;
}
if (strcmp(argv[i], "--afl") == 0) {
if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
exit(0);
}
// if a -l library is linked and no .so is found but an .a archive is there
// then the archive will be used. So we have to emulate this and check
// if an archive will be used and if yes we will instrument it too
libdir_file[0] = 0;
libdir_index = libdir_cnt;
if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 &&
strncmp(argv[i], "-lgcc", 5) != 0) {
u8 found = 0;
for (uint32_t j = 0; j < libdir_cnt && !found; j++) {
snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
argv[i] + 2, ".so");
if (access(libdir_file, R_OK) != 0) { // no .so found?
snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
argv[i] + 2, ".a");
if (access(libdir_file, R_OK) == 0) { // but .a found?
libdir_index = j;
found = 1;
if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
}
} else {
found = 1;
if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
}
}
}
// is the parameter an .a AR archive? If so, unpack and check its files
if (libdir_index < libdir_cnt ||
(argv[i][0] != '-' && strlen(argv[i]) > 2 &&
argv[i][strlen(argv[i]) - 1] == 'a' &&
argv[i][strlen(argv[i]) - 2] == '.')) {
// This gets a bit odd. I encountered several .a files being linked and
// where the same "foo.o" was in both .a archives. llvm-link does not
// like this so we have to work around that ...
u8 this_wd[4096], *this_ar;
u8 ar_params_cnt = 4;
u8 * ar_params[ar_params_cnt];
u8 * file = argv[i];
s32 pid, status;
DIR * arx;
struct dirent *dir_ent;
if (libdir_index < libdir_cnt) file = libdir_file;
if (ar_dir_cnt == 0) { // first archive, we setup up the basics
ar_dir = alloc_printf("%s/.afl-%u-%u.dir", tmp_dir, getpid(),
(u32)time(NULL));
if (mkdir(ar_dir, 0700) != 0)
FATAL("can not create temporary directory %s", ar_dir);
}
if (getcwd(this_wd, sizeof(this_wd)) == NULL)
FATAL("can not get the current working directory");
if (chdir(ar_dir) != 0)
FATAL("can not chdir to temporary directory %s", ar_dir);
if (file[0] == '/')
this_ar = file;
else
this_ar = alloc_printf("%s/%s", this_wd, file);
ar_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-ar");
ar_params[1] = "x";
ar_params[2] = this_ar;
ar_params[3] = NULL;
if (!be_quiet) OKF("Running ar unpacker on %s into %s", this_ar, ar_dir);
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (uint32_t j = 0; j < ar_params_cnt; j++)
SAYF(" \"%s\"", ar_params[j]);
SAYF("\n");
}
if (!(pid = fork())) {
execvp(ar_params[0], (char **)ar_params);
FATAL("Oops, failed to execute '%s'", ar_params[0]);
}
if (pid < 0) FATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) FATAL("waitpid() failed");
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
if (chdir(this_wd) != 0)
FATAL("can not chdir back to our working directory %s", this_wd);
if (!(arx = opendir(ar_dir))) FATAL("can not open directory %s", ar_dir);
while ((dir_ent = readdir(arx)) != NULL) {
u8 *ar_file = alloc_printf("%s/%s", ar_dir, dir_ent->d_name);
if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' &&
dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') {
if (passthrough || is_llvm_file(ar_file) == 0) {
if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) {
ld_params[ld_param_cnt++] = ar_file;
if (debug)
SAYF(cMGN "[D] " cRST "not a LTO link file: %s\n", ar_file);
}
} else {
if (is_duplicate(link_params, link_param_cnt, ar_file) == 0) {
if (we_link == 0) { // we have to honor order ...
ld_params[ld_param_cnt++] = final_file;
we_link = 1;
}
link_params[link_param_cnt++] = ar_file;
if (debug) SAYF(cMGN "[D] " cRST "is a link file: %s\n", ar_file);
}
}
} else
if (dir_ent->d_name[0] != '.' && !be_quiet)
WARNF("Unusual file found in ar archive %s: %s", argv[i], ar_file);
}
closedir(arx);
ar_dir_cnt++;
continue;
}
if (passthrough || argv[i][0] == '-' || is_llvm_file(argv[i]) == 0) {
// -O3 fucks up the CFG and instrumentation, so we downgrade to O2
// which is as we want things. Lets hope this is not too different
// in the various llvm versions!
if (strncmp(argv[i], "-plugin-opt=O", 13) == 0 &&
!getenv("AFL_DONT_OPTIMIZE"))
ld_params[ld_param_cnt++] = "-plugin-opt=O2";
else
ld_params[ld_param_cnt++] = argv[i];
} else {
if (we_link == 0) { // we have to honor order ...
ld_params[ld_param_cnt++] = final_file;
we_link = 1;
}
link_params[link_param_cnt++] = argv[i];
}
}
// if (have_lto == 0) ld_params[ld_param_cnt++] = AFL_CLANG_FLTO; // maybe we
// should not ...
ld_params[ld_param_cnt] = NULL;
link_params[link_param_cnt] = NULL;
opt_params[opt_param_cnt] = NULL;
inst_params[inst_param_cnt] = NULL;
}
/* clean AFL_PATH from PATH */
void clean_path() {
char *tmp, *newpath = NULL, *path = getenv("PATH");
u8 done = 0;
if (debug)
SAYF(cMGN "[D]" cRST " old PATH=%s, AFL_PATH=%s\n", path, AFL_PATH);
// wipe AFL paths from PATH that we set
// we added two paths so we remove the two paths
while (!done) {
if (*path == 0)
done = 1;
else if (*path++ == ':')
done = 1;
}
while (*path == ':')
path++;
// AFL_PATH could be additionally in PATH so check and remove to not call our
// 'ld'
const size_t pathlen = strlen(path);
const size_t afl_pathlen = strlen(AFL_PATH);
newpath = malloc(pathlen + 1);
if (strcmp(AFL_PATH, "/bin") != 0 && strcmp(AFL_PATH, "/usr/bin") != 0 &&
afl_pathlen > 1 && (tmp = strstr(path, AFL_PATH)) != NULL && // it exists
(tmp == path ||
(tmp > path &&
tmp[-1] == ':')) && // either starts with it or has a colon before
(tmp + afl_pathlen == path + pathlen ||
(tmp + afl_pathlen <
path + (pathlen && tmp[afl_pathlen] ==
':')) // end with it or has a colon at the end
)) {
int one_colon = 1;
if (tmp > path) {
memcpy(newpath, path, tmp - path);
newpath[tmp - path - 1] = 0; // remove ':'
one_colon = 0;
}
if (tmp + afl_pathlen < path + pathlen) tmp += afl_pathlen + one_colon;
setenv("PATH", newpath, 1);
} else
setenv("PATH", path, 1);
if (debug) SAYF(cMGN "[D]" cRST " new PATH=%s\n", getenv("PATH"));
free(newpath);
}
/* Main entry point */
int main(int argc, char **argv) {
s32 pid, i;
int status;
u8 *ptr, exe[4096], exe2[4096], proc[32], val[2] = " ";
int have_afl_ld_caller = 0;
if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
if (getenv("AFL_LD") != NULL)
SAYF(cCYA "afl-ld" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de> (level %d)\n",
have_afl_ld_caller);
} else
be_quiet = 1;
if (getenv("AFL_DEBUG") != NULL) debug = 1;
if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
if (real_ld == NULL || strlen(real_ld) < 2) real_ld = "/bin/ld";
if (real_ld != NULL && real_ld[0] != '/')
real_ld = alloc_printf("/bin/%s", real_ld);
if ((ptr = getenv("AFL_LD_CALLER")) != NULL) have_afl_ld_caller = atoi(ptr);
val[0] = 0x31 + have_afl_ld_caller;
setenv("AFL_LD_CALLER", val, 1);
if (debug) {
SAYF(cMGN "[D] " cRST
"AFL_LD=%s, set AFL_LD_CALLER=%s, have_afl_ld_caller=%d, "
"real_ld=%s\n",
getenv("AFL_LD"), val, have_afl_ld_caller, real_ld);
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < argc; i++)
SAYF(" \"%s\"", argv[i]);
SAYF("\n");
}
sprintf(proc, "/proc/%d/exe", getpid());
if (readlink(proc, exe, sizeof(exe) - 1) > 0) {
if (readlink(real_ld, exe2, sizeof(exe2) - 1) < 1) exe2[0] = 0;
exe[sizeof(exe) - 1] = 0;
exe[sizeof(exe2) - 1] = 0;
if (strcmp(exe, real_ld) == 0 || strcmp(exe, exe2) == 0)
PFATAL(cLRD "[!] " cRST
"Error: real 'ld' path points to afl-ld, set AFL_REAL_LD to "
"the real 'ld' program!");
}
if (have_afl_ld_caller > 1)
PFATAL(cLRD "[!] " cRST
"Error: afl-ld calls itself in a loop, set AFL_REAL_LD to the "
"real 'ld' program!");
if (argc < 2) {
SAYF(
"\n"
"This is a helper application for afl-fuzz. It is a wrapper around GNU "
"'ld',\n"
"executed by the toolchain whenever using "
"afl-clang-lto/afl-clang-lto++.\n"
"You probably don't want to run this program directly.\n\n"
"Environment variables:\n"
" AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n"
" AFL_REAL_LD point to the real ld if necessary\n"
"\nafl-ld was compiled with the fixed real 'ld' path of %s and the "
"clang "
"bin path of %s\n\n",
real_ld, LLVM_BINDIR);
exit(1);
}
if (getenv("AFL_LD") == NULL) {
/* if someone install clang/ld into the same directory as afl++ then
they are out of luck ... */
if (have_afl_ld_caller == 1) { clean_path(); }
if (real_ld != NULL && strlen(real_ld) > 1) execvp(real_ld, argv);
execvp("ld", argv); // fallback
PFATAL("Oops, failed to execute 'ld' - check your PATH");
}
atexit(at_exit_handler); // ensure to wipe temp files if things fail
edit_params(argc, argv); // here most of the magic happens :-)
if (debug)
SAYF(cMGN "[D] " cRST
"param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n",
ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt,
inst_param_cnt);
if (!just_version) {
if (we_link == 0) {
if (!getenv("AFL_QUIET"))
WARNF("No LTO input file found, cannot instrument!");
} else {
/* first we link all files */
if (!be_quiet) OKF("Running bitcode linker, creating %s", linked_file);
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < link_param_cnt; i++)
SAYF(" \"%s\"", link_params[i]);
SAYF("\n");
}
if (!(pid = fork())) {
execvp(link_params[0], (char **)link_params);
FATAL("Oops, failed to execute '%s'", link_params[0]);
}
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (WEXITSTATUS(status) != 0) {
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD
"\n[-] PROGRAM ABORT : " cRST);
SAYF(
"llvm-link failed! Probable causes:\n\n"
" #1 If the error is \"linking globals named '...': symbol "
"multiply defined\"\n"
" then there is nothing we can do - llvm-link is missing an "
"important feature\n\n"
" #2 If the error is \"expected top-level entity\" and then "
"binary output, this\n"
" is because the same file is present in different .a archives "
"in different\n"
" formats. This can be fixed by manual doing the steps afl-ld "
"is doing but\n"
" programmatically - sorry!\n\n");
exit(WEXITSTATUS(status));
}
/* then we perform an optimization on the collected objects files */
if (!be_quiet)
OKF("Performing optimization via opt, creating %s", modified_file);
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < opt_param_cnt; i++)
SAYF(" \"%s\"", opt_params[i]);
SAYF("\n");
}
if (!(pid = fork())) {
execvp(opt_params[0], (char **)opt_params);
FATAL("Oops, failed to execute '%s'", opt_params[0]);
}
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
/* then we run the instrumentation through the optimizer */
if (!be_quiet)
OKF("Performing instrumentation via opt, creating %s", final_file);
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < inst_param_cnt; i++)
SAYF(" \"%s\"", inst_params[i]);
SAYF("\n");
}
if (!(pid = fork())) {
execvp(inst_params[0], (char **)inst_params);
FATAL("Oops, failed to execute '%s'", inst_params[0]);
}
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
}
/* next step - run the linker! :-) */
}
if (!be_quiet) OKF("Running real linker %s", real_ld);
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
for (i = 0; i < ld_param_cnt; i++)
SAYF(" \"%s\"", ld_params[i]);
SAYF("\n");
}
if (!(pid = fork())) {
clean_path();
unsetenv("AFL_LD");
if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
execvp("ld", (char **)ld_params); // fallback
FATAL("Oops, failed to execute 'ld' - check your PATH");
}
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
if (!just_version) {
if (!getenv("AFL_KEEP_ASSEMBLY")) {
if (linked_file) {
unlink(linked_file);
linked_file = NULL;
}
if (modified_file) {
unlink(modified_file);
modified_file = NULL;
}
if (final_file) {
unlink(final_file);
final_file = NULL;
}
if (ar_dir != NULL) {
wipe_directory(ar_dir);
ar_dir = NULL;
}
} else {
if (!be_quiet) {
SAYF(
"[!] afl-ld: keeping link file %s, optimized bitcode %s and "
"instrumented bitcode %s",
linked_file, modified_file, final_file);
if (ar_dir_cnt > 0 && ar_dir)
SAYF(" and ar archive unpack directory %s", ar_dir);
SAYF("\n");
}
}
if (status == 0) {
if (!be_quiet) OKF("Linker was successful");
} else {
SAYF(cLRD "[-] " cRST
"Linker failed, please investigate and send a bug report. Most "
"likely an 'ld' option is incompatible with %s. Try "
"AFL_KEEP_ASSEMBLY=1 and AFL_DEBUG=1 for replaying.\n",
AFL_CLANG_FLTO);
}
}
exit(WEXITSTATUS(status));
}

View File

@ -0,0 +1,427 @@
/*
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
Written by Laszlo Szekeres <lszekeres@google.com> and
Michal Zalewski
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
from afl-as.c are Michal's fault.
Copyright 2015, 2016 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 library is plugged into LLVM when invoking clang through afl-clang-fast.
It tells the compiler to add code roughly equivalent to the bits discussed
in ../afl-as.h.
*/
// CONFIG OPTION:
// If #define USE_SPLIT is used, then the llvm::SplitEdge function is used
// instead of our own implementation. Ours looks better and will
// compile everywhere. But it is not working for complex code. yet. damn.
#define USE_SPLIT
#define AFL_LLVM_PASS
#include "config.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <list>
#include <string>
#include <fstream>
#include <sys/time.h>
#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
typedef long double max_align_t;
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#ifdef USE_SPLIT
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#endif
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#endif
using namespace llvm;
namespace {
class AFLLTOPass : public ModulePass {
public:
static char ID;
AFLLTOPass() : ModulePass(ID) {
char *ptr;
if (getenv("AFL_DEBUG")) debug = 1;
if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE)
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
ptr, MAP_SIZE - 1);
}
#ifdef USE_SPLIT
void getAnalysisUsage(AnalysisUsage &AU) const override {
ModulePass::getAnalysisUsage(AU);
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
}
#endif
// Calculate the number of average collisions that would occur if all
// location IDs would be assigned randomly (like normal afl/afl++).
// This uses the "balls in bins" algorithm.
unsigned long long int calculateCollisions(uint32_t edges) {
double bins = MAP_SIZE;
double balls = edges;
double step1 = 1 - (1 / bins);
double step2 = pow(step1, balls);
double step3 = bins * step2;
double step4 = round(step3);
unsigned long long int empty = step4;
unsigned long long int collisions = edges - (MAP_SIZE - empty);
return collisions;
}
// Get the internal llvm name of a basic block
// This is an ugly debug support so it is commented out :-)
/*
static char *getBBName(const BasicBlock *BB) {
static char *name;
if (!BB->getName().empty()) {
name = strdup(BB->getName().str().c_str());
return name;
}
std::string Str;
raw_string_ostream OS(Str);
BB->printAsOperand(OS, false);
name = strdup(OS.str().c_str());
return name;
}
*/
static bool isBlacklisted(const Function *F) {
static const char *Blacklist[] = {
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign.",
"__afl_", "_fini", "__libc_csu"
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
}
bool runOnModule(Module &M) override;
protected:
int afl_global_id = 1, debug = 0;
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
};
} // namespace
bool AFLLTOPass::runOnModule(Module &M) {
LLVMContext &C = M.getContext();
IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
struct timeval tv;
struct timezone tz;
u32 rand_seed;
/* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
gettimeofday(&tv, &tz);
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
AFL_SR(rand_seed);
/* Show a banner */
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-llvm-lto" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
} else
be_quiet = 1;
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#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");
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
/* Instrument all the things! */
int inst_blocks = 0;
for (auto &F : M) {
if (F.size() < 2) continue;
if (isBlacklisted(&F)) continue;
#ifdef USE_SPLIT
// DominatorTree &DT =
// getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); LoopInfo & LI =
// getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
#endif
std::vector<BasicBlock *> InsBlocks;
for (auto &BB : F) {
uint32_t succ = 0;
for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB); SI != SE;
++SI)
if ((*SI)->size() > 0) succ++;
if (succ < 2) // no need to instrument
continue;
InsBlocks.push_back(&BB);
}
if (InsBlocks.size() > 0) {
uint32_t i = InsBlocks.size();
do {
--i;
BasicBlock * origBB = &(*InsBlocks[i]);
std::vector<BasicBlock *> Successors;
Instruction * TI = origBB->getTerminator();
for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB);
SI != SE; ++SI) {
BasicBlock *succ = *SI;
Successors.push_back(succ);
}
if (TI == NULL || TI->getNumSuccessors() < 2) continue;
// if (Successors.size() != TI->getNumSuccessors())
// FATAL("Different successor numbers %lu <-> %u\n", Successors.size(),
// TI->getNumSuccessors());
for (uint32_t j = 0; j < Successors.size(); j++) {
#ifdef USE_SPLIT
BasicBlock *newBB = llvm::SplitEdge(origBB, Successors[j]);
#else
BasicBlock *newBB = BasicBlock::Create(C, "", &F, nullptr);
#endif
if (!newBB) {
if (!be_quiet) WARNF("Split failed!");
continue;
}
#ifdef USE_SPLIT
BasicBlock::iterator IP = newBB->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
#else
IRBuilder<> IRB(&(*newBB));
#endif
/* Set the ID of the inserted basic block */
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, afl_global_id++);
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
/* Update bitmap */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *Incr = IRB.CreateAdd(Counter, One);
#if LLVM_VERSION_MAJOR < 9
if (neverZero_counters_str !=
NULL) { // with llvm 9 we make this the default as the bug in
// llvm is then fixed
#endif
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
#if LLVM_VERSION_MAJOR < 9
}
#endif
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
#ifdef USE_SPLIT
// nothing
#else
// Unconditional jump to the destination BB
IRB.CreateBr(Successors[j]);
// Replace the original destination to this newly inserted BB
origBB->replacePhiUsesWith(Successors[j], newBB);
BasicBlock *S = Successors[j];
S->replacePhiUsesWith(origBB, newBB);
TI->setSuccessor(j, newBB);
#endif
// done :)
inst_blocks++;
}
} while (i > 0);
}
}
// save highest location ID to global variable
if (afl_global_id > MAP_SIZE) {
uint32_t pow2map = 1, map = afl_global_id;
while ((map = map >> 1))
pow2map++;
FATAL(
"We have %u blocks to instrument but the map size is only %u! Edit "
"config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
"afl-fuzz and llvm_mode.",
afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map);
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
GlobalVariable *AFLFinalLoc = new GlobalVariable(
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0,
GlobalVariable::GeneralDynamicTLSModel, 0, false);
ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id);
AFLFinalLoc->setAlignment(4);
AFLFinalLoc->setInitializer(const_loc);
}
/* Say something nice. */
if (!be_quiet) {
if (!inst_blocks)
WARNF("No instrumentation targets found.");
else {
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 with no collisions (on average %llu "
"collisions would be in afl-gcc/afl-clang-fast) (%s mode).",
inst_blocks, calculateCollisions(inst_blocks), modeline);
}
}
return true;
}
char AFLLTOPass::ID = 0;
static void registerAFLLTOPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLLTOPass());
}
static RegisterPass<AFLLTOPass> X("afl-lto", "afl++ LTO instrumentation pass",
false, false);
static RegisterStandardPasses RegisterAFLLTOPass(
PassManagerBuilder::EP_OptimizerLast, registerAFLLTOPass);

View File

@ -0,0 +1,267 @@
/*
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
Written by Laszlo Szekeres <lszekeres@google.com> and
Michal Zalewski
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
from afl-as.c are Michal's fault.
Copyright 2015, 2016 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 library is plugged into LLVM when invoking clang through afl-clang-fast.
It tells the compiler to add code roughly equivalent to the bits discussed
in ../afl-as.h.
*/
#define AFL_LLVM_PASS
#include "config.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <list>
#include <string>
#include <fstream>
#include <sys/time.h>
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/IR/CFG.h"
using namespace llvm;
namespace {
class AFLwhitelist : public ModulePass {
public:
static char ID;
AFLwhitelist() : ModulePass(ID) {
int entries = 0;
if (getenv("AFL_DEBUG")) debug = 1;
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);
entries++;
}
} else
PFATAL("afl-llvm-lto-whitelist.so loaded without AFL_LLVM_WHITELIST?!");
if (debug)
SAYF(cMGN "[D] " cRST "loaded whitelist %s with %d entries\n",
instWhiteListFilename, entries);
}
// ripped from aflgo
static bool isBlacklisted(const Function *F) {
static const SmallVector<std::string, 5> Blacklist = {
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
}
bool runOnModule(Module &M) override;
// StringRef getPassName() const override {
// return "American Fuzzy Lop Instrumentation";
// }
protected:
std::list<std::string> myWhitelist;
int debug = 0;
};
} // namespace
char AFLwhitelist::ID = 0;
bool AFLwhitelist::runOnModule(Module &M) {
/* Show a banner */
char be_quiet = 0;
if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "afl-llvm-lto-whitelist" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
} else if (getenv("AFL_QUIET"))
be_quiet = 1;
for (auto &F : M) {
if (isBlacklisted(&F)) continue;
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (!myWhitelist.empty()) {
bool instrumentBlock = false;
/* Get the current location using debug information.
* For now, just instrument the block if we are not able
* to determine our location. */
DebugLoc Loc = IP->getDebugLoc();
if (Loc) {
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
unsigned int instLine = cDILoc->getLine();
StringRef 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();
}
}
(void)instLine;
/* 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) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename
* specified in the list. */
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(
instFilename.str().length() - it->length(),
it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
/* Either we couldn't figure out our location or the location is
* not whitelisted, so we skip instrumentation.
* We do this by renaming the function. */
if (!instrumentBlock) {
if (F.getName().compare("main") == 0 ||
F.getName().compare("start") == 0 ||
F.getName().compare("_start") == 0 ||
F.getName().compare("init") == 0 ||
F.getName().compare("_init") == 0) {
// We do not honor be_quiet for this one
WARNF("Cannot ignore functions main/init/start");
} else {
// StringRef newName = StringRef("ign.") + F.getName();
if (debug)
SAYF(cMGN "[D] " cRST "renamed %s to ign.%s\n",
F.getName().str().c_str(), F.getName().str().c_str());
Function *_F(&F);
_F->setName("ign." + F.getName());
}
} else if (debug)
SAYF(cMGN "[D] " cRST "function %s is in whitelist\n",
F.getName().str().c_str());
} else {
PFATAL("Whitelist is empty");
}
break;
}
}
return true;
}
static void registerAFLwhitelistpass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLwhitelist());
}
static RegisterStandardPasses RegisterAFLwhitelistpass(
PassManagerBuilder::EP_ModuleOptimizerEarly, registerAFLwhitelistpass);
static RegisterStandardPasses RegisterAFLwhitelistpass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLwhitelistpass);

View File

@ -2,12 +2,15 @@
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
Written by Laszlo Szekeres <lszekeres@google.com> and
Written by Laszlo Szekeres <lszekeres@google.com>,
Adrian Herrera <adrian.herrera@anu.edu.au>,
Michal Zalewski
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
from afl-as.c are Michal's fault.
NGRAM previous location coverage comes from Adrian Herrera.
Copyright 2015, 2016 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@ -27,7 +30,6 @@
#include "config.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -47,6 +49,7 @@ typedef long double max_align_t;
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_MAJOR > 3 || \
@ -58,6 +61,8 @@ typedef long double max_align_t;
#include "llvm/Support/CFG.h"
#endif
#include "llvm-ngram-coverage.h"
using namespace llvm;
namespace {
@ -118,6 +123,9 @@ class AFLCoverage : public ModulePass {
protected:
std::list<std::string> myWhitelist;
uint32_t ngram_size = 0;
uint32_t debug = 0;
char * ctx_str = NULL;
};
@ -125,12 +133,40 @@ class AFLCoverage : public ModulePass {
char AFLCoverage::ID = 0;
/* needed up to 3.9.0 */
#if LLVM_VERSION_MAJOR == 3 && \
(LLVM_VERSION_MINOR < 9 || \
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
uint64_t PowerOf2Ceil(unsigned in) {
uint64_t in64 = in - 1;
in64 |= (in64 >> 1);
in64 |= (in64 >> 2);
in64 |= (in64 >> 4);
in64 |= (in64 >> 8);
in64 |= (in64 >> 16);
in64 |= (in64 >> 32);
return in64 + 1;
}
#endif
/* #if LLVM_VERSION_STRING >= "4.0.1" */
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
#define AFL_HAVE_VECTOR_INTRINSICS 1
#endif
bool AFLCoverage::runOnModule(Module &M) {
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
#ifdef AFL_HAVE_VECTOR_INTRINSICS
IntegerType *IntLocTy =
IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
#endif
struct timeval tv;
struct timezone tz;
u32 rand_seed;
@ -145,9 +181,12 @@ bool AFLCoverage::runOnModule(Module &M) {
char be_quiet = 0;
if (getenv("AFL_DEBUG")) debug = 1;
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-llvm-pass" VERSION cRST " by <lszekeres@google.com>\n");
SAYF(cCYA "afl-llvm-pass" VERSION cRST
" by <lszekeres@google.com> and <adrian.herrera@anu.edu.au>\n");
} else
@ -170,32 +209,171 @@ bool AFLCoverage::runOnModule(Module &M) {
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#endif
unsigned PrevLocSize;
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
ctx_str = getenv("AFL_LLVM_CTX");
#ifdef AFL_HAVE_VECTOR_INTRINSICS
/* 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 == 1) ngram_size = 0;
if (ngram_size)
PrevLocSize = ngram_size - 1;
else
#else
if (ngram_size_str)
FATAL("Sorry, NGRAM branch coverage is not supported with llvm version %s!",
LLVM_VERSION_STRING);
#endif
PrevLocSize = 1;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
#endif
if (ctx_str && ngram_size_str)
FATAL("you must decide between NGRAM and CTX instrumentation");
/* 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;
if (ctx_str)
#ifdef __ANDROID__
GlobalVariable *AFLPrevLoc = new GlobalVariable(
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
GlobalVariable *AFLPrevLoc = new GlobalVariable(
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
// other constants we need
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
LoadInst *PrevCtx; // CTX sensitive coverage
/* Instrument all the things! */
int inst_blocks = 0;
for (auto &F : M) {
int has_calls = 0;
if (debug)
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
F.size());
if (isBlacklisted(&F)) continue;
// AllocaInst *CallingContext = nullptr;
if (ctx_str && F.size() > 1) { // Context sensitive coverage
// load the context ID of the previous function and write to to a local
// variable on the stack
auto bb = &F.getEntryBlock();
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
PrevCtx = IRB.CreateLoad(AFLContext);
PrevCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// 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() < 2)
continue;
else {
has_calls = 1;
break;
}
}
}
}
// if yes we store a context ID for this function in the global var
if (has_calls) {
ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(MAP_SIZE));
StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
@ -310,6 +488,22 @@ bool AFLCoverage::runOnModule(Module &M) {
}
// in CTX mode we have to restore the original context for the caller -
// she might be calling other functions which need the correct CTX
if (ctx_str && has_calls) {
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));
}
}
if (AFL_R(100) >= inst_ratio) continue;
/* Make up cur_loc */
@ -356,20 +550,50 @@ bool AFLCoverage::runOnModule(Module &M) {
// fprintf(stderr, " == %d\n", more_than_one);
if (more_than_one != 1) continue;
#endif
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc);
ConstantInt *CurLoc;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
CurLoc = ConstantInt::get(IntLocTy, cur_loc);
else
#endif
CurLoc = ConstantInt::get(Int32Ty, cur_loc);
/* Load prev_loc */
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.CreateXorReduce(PrevLoc);
else
#endif
if (ctx_str)
PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLoc, PrevCtx), Int32Ty);
else
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx =
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, CurLoc));
Value *MapPtrIdx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
MapPtrIdx = IRB.CreateGEP(
MapPtr,
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, CurLoc), Int32Ty));
else
#endif
MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
/* Update bitmap */
@ -449,12 +673,32 @@ bool AFLCoverage::runOnModule(Module &M) {
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* Set prev_loc to cur_loc >> 1 */
/* Update prev_loc history vector (by placing cur_loc at the head of the
vector and shuffle the other elements back by one) */
StoreInst *Store =
IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc);
StoreInst *Store;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size) {
Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
Value *UpdatedPrevLoc = IRB.CreateInsertElement(
ShuffledPrevLoc, IRB.CreateLShr(CurLoc, (uint64_t)1), (uint64_t)0);
Store = IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc);
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
} else
#endif
{
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
AFLPrevLoc);
}
inst_blocks++;
}
@ -470,10 +714,11 @@ bool AFLCoverage::runOnModule(Module &M) {
else {
char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
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 (%s mode, ratio %u%%).", inst_blocks,
modeline, inst_ratio);

View File

@ -26,6 +26,7 @@
#include "config.h"
#include "types.h"
#include "cmplog.h"
#include "llvm-ngram-coverage.h"
#include <stdio.h>
#include <stdlib.h>
@ -41,6 +42,10 @@
#include <sys/wait.h>
#include <sys/types.h>
#ifdef __linux__
#include "snapshot-inl.h"
#endif
/* This is a somewhat ugly hack for the experimental 'trace-pc-guard' mode.
Basically, we need to make sure that the forkserver is initialized after
the LLVM-generated runtime initialization pass, not before. */
@ -62,13 +67,18 @@ u8 __afl_area_initial[MAP_SIZE];
u8 *__afl_area_ptr = __afl_area_initial;
#ifdef __ANDROID__
u32 __afl_prev_loc;
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
u32 __afl_final_loc;
u32 __afl_prev_ctx;
u32 __afl_cmp_counter;
#else
__thread u32 __afl_prev_loc;
__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
__thread u32 __afl_final_loc;
__thread u32 __afl_prev_ctx;
__thread u32 __afl_cmp_counter;
#endif
struct cmp_map *__afl_cmp_map;
__thread u32 __afl_cmp_counter;
/* Running in persistent mode? */
@ -95,7 +105,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);
}
@ -107,7 +117,7 @@ static void __afl_map_shm(void) {
close(shm_fd);
shm_fd = -1;
printf("mmap() failed\n");
fprintf(stderr, "mmap() failed\n");
exit(2);
}
@ -143,7 +153,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);
}
@ -156,7 +166,7 @@ static void __afl_map_shm(void) {
close(shm_fd);
shm_fd = -1;
printf("mmap() failed\n");
fprintf(stderr, "mmap() failed\n");
exit(2);
}
@ -174,10 +184,113 @@ static void __afl_map_shm(void) {
}
#ifdef __linux__
static void __afl_start_snapshots(void) {
static u8 tmp[4];
s32 child_pid;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
while (1) {
u32 was_killed;
int status;
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
process. */
if (child_stopped && was_killed) {
child_stopped = 0;
if (waitpid(child_pid, &status, 0) < 0) _exit(1);
}
if (!child_stopped) {
/* Once woken up, create a clone of our process. */
child_pid = fork();
if (child_pid < 0) _exit(1);
/* In child process: close fds, resume execution. */
if (!child_pid) {
signal(SIGCHLD, old_sigchld_handler);
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (!afl_snapshot_do()) { raise(SIGSTOP); }
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
return;
}
} else {
/* Special handling for persistent mode: if the child is alive but
currently stopped, simply restart it with SIGCONT. */
kill(child_pid, SIGCONT);
child_stopped = 0;
}
/* In parent process: write PID to pipe, then wait for child. */
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1);
if (waitpid(child_pid, &status, WUNTRACED) < 0) _exit(1);
/* In persistent mode, the child stops itself with SIGSTOP to indicate
a successful run. In this case, we want to wake it up without forking
again. */
if (WIFSTOPPED(status)) child_stopped = 1;
/* Relay wait status to pipe, then loop back. */
if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1);
}
}
#endif
/* Fork server logic. */
static void __afl_start_forkserver(void) {
#ifdef __linux__
if (!is_persistent && !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
afl_snapshot_init() >= 0) {
__afl_start_snapshots();
return;
}
#endif
static u8 tmp[4];
s32 child_pid;
@ -260,7 +373,8 @@ static void __afl_start_forkserver(void) {
}
/* A simplified persistent mode handler, used as explained in README.llvm. */
/* A simplified persistent mode handler, used as explained in
* llvm_mode/README.md. */
int __afl_persistent_loop(unsigned int max_cnt) {
@ -278,7 +392,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
memset(__afl_area_ptr, 0, MAP_SIZE);
__afl_area_ptr[0] = 1;
__afl_prev_loc = 0;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
}
@ -295,7 +409,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
raise(SIGSTOP);
__afl_area_ptr[0] = 1;
__afl_prev_loc = 0;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
return 1;
@ -346,7 +460,7 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
It remains non-operational in the traditional, plugin-backed LLVM mode.
For more info about 'trace-pc-guard', see README.llvm.
For more info about 'trace-pc-guard', see llvm_mode/README.md.
The first function (__sanitizer_cov_trace_pc_guard) is called back on every
edge (as opposed to every basic block). */
@ -399,13 +513,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
///// CmpLog instrumentation
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
void __cmplog_ins_hook1(uint8_t Arg1, uint8_t Arg2) {
return;
}
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
if (!__afl_cmp_map) return;
@ -429,7 +543,7 @@ void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
}
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
if (!__afl_cmp_map) return;
@ -450,7 +564,7 @@ void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
}
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
if (!__afl_cmp_map) return;
@ -472,19 +586,33 @@ void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
}
#if defined(__APPLE__)
#pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1
#pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2
#pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4
#pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8
#pragma weak __sanitizer_cov_trace_const_cmp1 = __cmplog_ins_hook1
#pragma weak __sanitizer_cov_trace_const_cmp2 = __cmplog_ins_hook2
#pragma weak __sanitizer_cov_trace_const_cmp4 = __cmplog_ins_hook4
#pragma weak __sanitizer_cov_trace_const_cmp8 = __cmplog_ins_hook8
#pragma weak __sanitizer_cov_trace_cmp1 = __cmplog_ins_hook1
#pragma weak __sanitizer_cov_trace_cmp2 = __cmplog_ins_hook2
#pragma weak __sanitizer_cov_trace_cmp4 = __cmplog_ins_hook4
#pragma weak __sanitizer_cov_trace_cmp8 = __cmplog_ins_hook8
#else
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp1")));
__attribute__((alias("__cmplog_ins_hook1")));
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp2")));
__attribute__((alias("__cmplog_ins_hook2")));
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp4")));
__attribute__((alias("__cmplog_ins_hook4")));
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp8")));
__attribute__((alias("__cmplog_ins_hook8")));
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2)
__attribute__((alias("__cmplog_ins_hook1")));
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2)
__attribute__((alias("__cmplog_ins_hook2")));
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2)
__attribute__((alias("__cmplog_ins_hook4")));
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2)
__attribute__((alias("__cmplog_ins_hook8")));
#endif /* defined(__APPLE__) */
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
@ -526,6 +654,8 @@ static int area_is_mapped(void* ptr, size_t len) {
void __cmplog_rtn_hook(void *ptr1, void *ptr2) {
if (!__afl_cmp_map) return;
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);

View File

@ -0,0 +1,404 @@
/*
american fuzzy lop++ - LLVM CmpLog instrumentation
--------------------------------------------------
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2015, 2016 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 <list>
#include <string>
#include <fstream>
#include <sys/time.h>
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
using namespace llvm;
namespace {
class CmpLogInstructions : public ModulePass {
public:
static char ID;
CmpLogInstructions() : ModulePass(ID) {
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);
}
}
}
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR < 4
const char *getPassName() const override {
#else
StringRef getPassName() const override {
#endif
return "cmplog instructions";
}
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
private:
bool hookInstrs(Module &M);
};
} // namespace
char CmpLogInstructions::ID = 0;
bool CmpLogInstructions::hookInstrs(Module &M) {
std::vector<Instruction *> icomps;
LLVMContext & C = M.getContext();
Type * VoidTy = Type::getVoidTy(C);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookIns1 = cast<Function>(c1);
#else
FunctionCallee cmplogHookIns1 = c1;
#endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookIns2 = cast<Function>(c2);
#else
FunctionCallee cmplogHookIns2 = c2;
#endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookIns4 = cast<Function>(c4);
#else
FunctionCallee cmplogHookIns4 = c4;
#endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookIns8 = cast<Function>(c8);
#else
FunctionCallee cmplogHookIns8 = c8;
#endif
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
for (auto &BB : F) {
if (!myWhitelist.empty()) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
bool instrumentBlock = false;
/* Get the current location using debug information.
* For now, just instrument the block if we are not able
* to determine our location. */
DebugLoc Loc = IP->getDebugLoc();
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
if (Loc) {
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
unsigned int instLine = cDILoc->getLine();
StringRef 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();
}
}
(void)instLine;
/* 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) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename
* specified in the list. */
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(
instFilename.str().length() - it->length(),
it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
#else
if (!Loc.isUnknown()) {
DILocation cDILoc(Loc.getAsMDNode(C));
unsigned int instLine = cDILoc.getLineNumber();
StringRef instFilename = cDILoc.getFilename();
(void)instLine;
/* 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) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename
* specified in the list. */
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) continue;
}
for (auto &IN : BB) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
if (selectcmpInst->getPredicate() == CmpInst::ICMP_EQ ||
selectcmpInst->getPredicate() == CmpInst::ICMP_NE ||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGT ||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGT ||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULT ||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLT ||
selectcmpInst->getPredicate() == CmpInst::ICMP_UGE ||
selectcmpInst->getPredicate() == CmpInst::ICMP_SGE ||
selectcmpInst->getPredicate() == CmpInst::ICMP_ULE ||
selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) {
auto op0 = selectcmpInst->getOperand(0);
auto op1 = selectcmpInst->getOperand(1);
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
/* this is probably not needed but we do it anyway */
if (!intTyOp0 || !intTyOp1) { continue; }
icomps.push_back(selectcmpInst);
}
}
}
}
}
if (!icomps.size()) return false;
if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp instructions\n";
for (auto &selectcmpInst : icomps) {
IRBuilder<> IRB(selectcmpInst->getParent());
IRB.SetInsertPoint(selectcmpInst);
auto op0 = selectcmpInst->getOperand(0);
auto op1 = selectcmpInst->getOperand(1);
IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth()
? intTyOp0->getBitWidth()
: intTyOp1->getBitWidth();
std::vector<Value *> args;
args.push_back(op0);
args.push_back(op1);
switch (max_size) {
case 8: IRB.CreateCall(cmplogHookIns1, args, "tmp"); break;
case 16: IRB.CreateCall(cmplogHookIns2, args, "tmp"); break;
case 32: IRB.CreateCall(cmplogHookIns4, args, "tmp"); break;
case 64: IRB.CreateCall(cmplogHookIns8, args, "tmp"); break;
default: break;
}
}
return true;
}
bool CmpLogInstructions::runOnModule(Module &M) {
if (getenv("AFL_QUIET") == NULL)
llvm::errs()
<< "Running cmplog-instructions-pass by andreafioraldi@gmail.com\n";
else
be_quiet = 1;
hookInstrs(M);
verifyModule(M);
return true;
}
static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmpLogInstructions();
PM.add(p);
}
static RegisterStandardPasses RegisterCmpLogInstructionsPass(
PassManagerBuilder::EP_OptimizerLast, registerCmpLogInstructionsPass);
static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);

View File

@ -92,6 +92,7 @@ class CmpLogRoutines : public ModulePass {
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
private:
bool hookRtns(Module &M);
@ -274,7 +275,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
}
if (!calls.size()) return false;
errs() << "Hooking " << calls.size() << " calls with pointers as arguments\n";
if (!be_quiet)
errs() << "Hooking " << calls.size()
<< " calls with pointers as arguments\n";
for (auto &callInst : calls) {
@ -302,6 +305,8 @@ bool CmpLogRoutines::runOnModule(Module &M) {
if (getenv("AFL_QUIET") == NULL)
llvm::errs()
<< "Running cmplog-routines-pass by andreafioraldi@gmail.com\n";
else
be_quiet = 1;
hookRtns(M);
verifyModule(M);

View File

@ -25,6 +25,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
@ -91,6 +92,7 @@ class CompareTransform : public ModulePass {
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
private:
bool transformCmps(Module &M, const bool processStrcmp,
@ -349,6 +351,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
if (!calls.size()) return false;
if (!be_quiet)
errs() << "Replacing " << calls.size()
<< " calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n";
@ -408,6 +411,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; }
if (!be_quiet)
errs() << callInst->getCalledFunction()->getName() << ": len " << constLen
<< ": " << ConstStr << "\n";
@ -499,6 +503,8 @@ bool CompareTransform::runOnModule(Module &M) {
if (isatty(2) && getenv("AFL_QUIET") == NULL)
llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, "
"extended by heiko@hexco.de\n";
else
be_quiet = 1;
transformCmps(M, true, true, true, true, true);
verifyModule(M);

View File

@ -0,0 +1,18 @@
#ifndef AFL_NGRAM_CONFIG_H
#define AFL_NGRAM_CONFIG_H
#include "../config.h"
#if (MAP_SIZE_POW2 <= 16)
typedef u16 PREV_LOC_T;
#elif (MAP_SIZE_POW2 <= 32)
typedef u32 PREV_LOC_T;
#else
typedef u64 PREV_LOC_T;
#endif
/* Maximum ngram size */
#define NGRAM_SIZE_MAX 16U
#endif

View File

@ -27,6 +27,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Pass.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
@ -105,6 +106,7 @@ class SplitComparesTransform : public ModulePass {
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
private:
int enableFPSplit;
@ -1233,8 +1235,8 @@ bool SplitComparesTransform::runOnModule(Module &M) {
int bitw = 64;
char *bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
if (!bitw_env) bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
if (bitw_env) { bitw = atoi(bitw_env); }
enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL;
@ -1243,7 +1245,8 @@ bool SplitComparesTransform::runOnModule(Module &M) {
simplifyIntSignedness(M);
if (isatty(2) && getenv("AFL_QUIET") == NULL) {
if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
getenv("AFL_DEBUG") != NULL) {
errs() << "Split-compare-pass by laf.intel@gmail.com, extended by "
"heiko@hexco.de\n";
@ -1252,11 +1255,14 @@ bool SplitComparesTransform::runOnModule(Module &M) {
errs() << "Split-floatingpoint-compare-pass: " << splitFPCompares(M)
<< " FP comparisons splitted\n";
}
} else
be_quiet = 1;
switch (bitw) {
case 64:
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
@ -1266,6 +1272,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
#endif
case 32:
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
@ -1275,6 +1282,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
#endif
case 16:
if (!be_quiet)
errs() << "Split-integer-compare-pass " << bitw
<< "bit: " << splitIntCompares(M, bitw) << " splitted\n";
@ -1282,7 +1290,7 @@ bool SplitComparesTransform::runOnModule(Module &M) {
break;
default:
errs() << "NOT Running split-compare-pass \n";
if (!be_quiet) errs() << "NOT Running split-compare-pass \n";
return false;
break;

View File

@ -26,6 +26,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
@ -125,6 +126,7 @@ class SplitSwitchesTransform : public ModulePass {
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
private:
bool splitSwitches(Module &M);
@ -472,6 +474,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
}
if (!switches.size()) return false;
if (!be_quiet)
errs() << "Rewriting " << switches.size() << " switch statements "
<< "\n";
@ -485,14 +488,15 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
BasicBlock *Default = SI->getDefaultDest();
unsigned bitw = Val->getType()->getIntegerBitWidth();
errs() << "switch: " << SI->getNumCases() << " cases " << bitw << " bit\n";
if (!be_quiet)
errs() << "switch: " << SI->getNumCases() << " cases " << bitw
<< " bit\n";
/* If there is only the default destination or the condition checks 8 bit or
* less, don't bother with the code below. */
if (!SI->getNumCases() || bitw <= 8) {
if (isatty(2) && getenv("AFL_QUIET") == NULL)
errs() << "skip trivial switch..\n";
if (!be_quiet) errs() << "skip trivial switch..\n";
continue;
}
@ -559,6 +563,8 @@ bool SplitSwitchesTransform::runOnModule(Module &M) {
if (isatty(2) && getenv("AFL_QUIET") == NULL)
llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n";
else
be_quiet = 1;
splitSwitches(M);
verifyModule(M);

Some files were not shown because too many files have changed in this diff Show More