Compare commits

...

498 Commits
2.63c ... 2.65c

Author SHA1 Message Date
87a693d1a9 Merge pull request #360 from AFLplusplus/dev
new code formatting + applied
2020-05-15 08:36:51 +02:00
49bd24144a v2.65c 2020-05-15 08:35:46 +02:00
182b8a4582 llvm_mode: lower llvm version reqs to 3.4 (LLInsTrim will not be
available)
2020-05-15 01:55:33 +02:00
97bddc8cfa added critical whitespace 2020-05-15 01:52:56 +02:00
a55e26959b fixed recursive clean 2020-05-15 01:31:02 +02:00
63e2222af1 code format 2020-05-15 01:24:27 +02:00
9637fe8a74 travis for focal 2020-05-15 00:58:17 +02:00
c084458294 updated 20.04 Dockerfile 2020-05-15 00:51:57 +02:00
498e9f4298 adding 20.04 test 2020-05-14 23:54:07 +02:00
13033034db nuicornafl build script fix setuptools check 2020-05-14 23:23:55 +02:00
749c63d3b3 removed accidental shell injection 2020-05-14 22:39:11 +02:00
73c2619c33 .gitignore: better be explicit 2020-05-14 22:30:44 +02:00
65f9553365 unicorn mode may run scripts 2020-05-14 22:25:50 +02:00
3f621c8ed4 update .gitignore 2020-05-14 21:57:32 +02:00
11f3b487ee corrected info about python 2020-05-14 21:51:51 +02:00
4c253aedae use --python flag to point to python executable for qemu build 2020-05-14 21:49:36 +02:00
efdad526ee darn IDE 2020-05-14 21:49:36 +02:00
4081a8f7b6 should install python3 setuptools here too 2020-05-14 21:49:36 +02:00
867f948bb2 create temp symlink to python3 for qemu mode if python isn't found 2020-05-14 21:49:36 +02:00
767ed8c5da add python setuptools to travis builds 2020-05-14 21:49:36 +02:00
f0aadc3d0b qemu build expects python on PATH 2020-05-14 21:49:36 +02:00
d95c4483fd correct binary already chosen before 2020-05-14 21:49:36 +02:00
00a147b244 info about py3 setuptools 2020-05-14 21:49:26 +02:00
74eae83b54 use only python3 in new builds 2020-05-14 21:47:04 +02:00
324b44872c unicornafl: python/module check with faster method 2020-05-14 21:13:36 +02:00
94a1d4d3ac test unicornafl: copy from build script 2020-05-14 20:32:04 +02:00
a3392007cd next try 2020-05-14 20:30:00 +02:00
4ac06a4eef and more 2020-05-14 20:10:10 +02:00
0495ded87d unicornafl build script more debug 2020-05-14 19:58:32 +02:00
64b80b3201 unicornafl build script: debugging version for travis 2020-05-14 19:23:07 +02:00
fa20eb1de7 GNUmakefile: add standard path for NetBSD, test for git and svn before use 2020-05-14 18:47:44 +02:00
ae15803bf1 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-05-14 18:41:44 +02:00
9e375179d8 test.sh: make sure the right python version (with setuptools available) is being used 2020-05-14 18:40:26 +02:00
460760d7b6 unicornafl build script: find matching python and setuptools 2020-05-14 18:00:48 +02:00
682b620922 fix afl-clang-fast help output 2020-05-14 16:25:07 +02:00
6b69cd2e57 Makefile: for convenience forward targets to GNUmake 2020-05-14 09:00:17 +00:00
56a86bb9e2 added unicornafl fix info 2020-05-14 01:35:35 +02:00
00ad2ffc61 unicornafl version 2020-05-14 01:33:03 +02:00
a16e92800d prefer python3 2020-05-14 01:20:33 +02:00
7c9ff4bfe7 if target crashes add LTO fixed map as a possible reason 2020-05-14 01:12:00 +02:00
d334093606 deprecated AFL_POST_LIBRARY 2020-05-14 01:00:11 +02:00
044bd3cb41 init/deinit need to be optional for post lib 2020-05-13 18:58:32 +02:00
4e192db13c better clean 2020-05-13 18:24:01 +02:00
8cc5442401 fix GNUmakefile 2020-05-13 18:20:06 +02:00
bd94d5fce7 unicornafl build script: python version is critical 2020-05-13 17:39:00 +02:00
b6be906082 GNUmakefile: avoid tabs 2020-05-13 17:03:59 +02:00
60a5df5262 code-format and slight -S/-M modifications 2020-05-13 16:49:00 +02:00
c384a17b41 GNUmakefile: add paths /usr/local/... for OpenBSD, add check for ASAN 2020-05-13 16:42:20 +00:00
6fdd6004f2 unicornafl build script: fix sed call for OpenBSD, use present python
bug fixes:
2020-05-13 16:39:25 +00:00
c4fe6f5277 Merge pull request #361 from rish9101/pre_save_format
Add post library API as custom mutator and rename pre_save
2020-05-13 16:39:23 +02:00
645e331559 Fix previous commit bugs 2020-05-13 19:46:30 +05:30
45bddcd808 Fix bugs, remove intial post library test 2020-05-13 19:25:23 +05:30
9627458ecc Add post library API as custom mutator and rename pre_save 2020-05-13 18:59:12 +05:30
f8b3d34225 move has_new_bits for better performance 2020-05-13 00:41:24 +02:00
5273c61cd8 Darwin tests: grep --binary-files=text for laf-intel and skipping of unittests 2020-05-12 23:19:51 +02:00
0c1c947aaf updated uc ref 2020-05-12 22:42:41 +02:00
6224ae1c60 test/test.sh: prefer python3 over python for unicornafl, avoid realpath and readlink dependencies 2020-05-12 20:59:48 +02:00
72f4a9f678 missing env var 2020-05-12 19:40:04 +02:00
060f4ea320 enforce mandatary custom functions 2020-05-12 17:05:12 +02:00
6177954773 fix custom mutators and add real test cases 2020-05-12 16:32:40 +02:00
7b40d7b942 new code formatting + applied 2020-05-12 11:12:25 +02:00
1317433a51 Merge pull request #359 from AFLplusplus/dev
push to master
2020-05-12 11:04:18 +02:00
a578d719e1 llvm_mode: more support for Darwin/MacOSX (WIP) 2020-05-12 10:34:52 +02:00
8bb10c3bf1 fix issue in describe_op showing time inside src 2020-05-12 09:20:02 +02:00
b920cd2f23 blacklist llvmfuzzer functions 2020-05-11 23:30:28 +02:00
38dac93f63 fix typos 2020-05-11 22:44:44 +02:00
6f66be12f6 merge makefile 2020-05-11 15:30:00 +02:00
4ee93331dc updated unicornafl 2020-05-11 15:11:11 +02:00
30a675ab87 silened warnings 2020-05-11 14:40:42 +02:00
845522f59b remove warnings 2020-05-11 13:34:57 +02:00
f37be09a92 fixed unicornafl bug 2020-05-11 13:18:06 +02:00
ed877f5e3e add missing include 2020-05-11 12:46:27 +02:00
d916403927 document workaround for targets with _init for LTO 2020-05-11 11:33:33 +02:00
41f6aa7940 bigger initial map when LTO 2020-05-11 10:45:20 +02:00
50a63777ec python formatter: enhance detection of #define, needed for multi line macros
@andreafioraldi : please have a look at it. Goal is to detect forms of ' # define' also.
2020-05-11 10:12:32 +02:00
26fe7a9d66 final code-format fixes, remove test-multiple-mutators when done 2020-05-10 15:53:47 +02:00
07a0e2caf7 hopefully final fixes from code-format disaster :-( 2020-05-10 15:36:46 +02:00
30bfd44dfd indenting preprocessor directives breaks compilation and cant be fixed, reverting ... :-( 2020-05-10 12:09:37 +02:00
26f8708fed fix warning, code format 2020-05-10 11:35:31 +02:00
3beec8d4fa clang-format: indent preprocessor directives, so nesting levels can be better seen 2020-05-10 11:11:40 +02:00
2e553bcd69 code-format 2020-05-10 10:24:24 +02:00
0e5a5f1805 Merge pull request #358 from rish9101/update_docs
Specify usage of multiple custom mutators
2020-05-10 08:59:36 +02:00
d02cfc54b6 LTO fixes for fuzzbench 2020-05-10 08:51:40 +02:00
7b9ac9d414 Specify usage of multiple custom mutators 2020-05-10 12:21:19 +05:30
515de0d68d Illumos biuld fix (#357) 2020-05-10 00:21:26 +02:00
1eeb6785ad Merge pull request #356 from devnexen/netbsd_build_fix_tokencap
NetBSD build fix
2020-05-09 20:39:18 +02:00
20392878f1 qemu_mode: make building warning free 2020-05-09 20:02:32 +02:00
102067d43d LLVMInsTrim.so.cc: fix for LLVM 3.8.0 2020-05-09 19:08:54 +02:00
6c88e21459 NetBSD build fix 2020-05-09 18:02:53 +01:00
041f19494e minor fixes 2020-05-09 18:51:33 +02:00
8e9f507bbc unicorn_mode/samples/persistent/Makefile: fix non-Linux support 2020-05-09 18:49:32 +02:00
c380819e02 remove debug output 2020-05-09 11:58:47 +02:00
fa84e52af0 custom mutator code enhancements and code-format 2020-05-09 11:35:54 +02:00
cf9238e09d Update docs and Changelog for custom_mutators (#355) 2020-05-09 00:01:11 +02:00
190f3024da Support multiple custom mutators (#282)
* Make a list of custom mutators using env variable

* Set up multiple custom mutators

* Add destroy custom mutator and changes to load_custom_mutator

* Use array instead of list, make changes to afl-fuzz-one for multiple mutators

* Make change to fuzz-one custom_queue_get to support multiple mutators

* Modify custom python mutator support

* Fix bug

* Fix missing afl->mutator->data

* Revert to list with max count

* Change custom_pre_save hook and code format

* Free custom_mutator struct in the list

* Add testcase for multiple custom mutators

* Resolve merge conflict
2020-05-08 20:08:27 +02:00
768053b6f2 add AFL_DEBUG check to all isatty checks 2020-05-08 16:28:39 +02:00
bdd2a412c4 change docs/README.md to symlink to toplevel README.md 2020-05-07 18:47:23 +02:00
d217c7df05 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-05-07 18:33:38 +02:00
9484da57ed convert docs/README.md into a symlink to toplevel README.md (helps website content) 2020-05-07 18:32:36 +02:00
ef2ccc8117 added AFL_LLVM_SKIPSINGLEBLOCK and changed default behaviour to instrument single block functions 2020-05-07 14:59:12 +02:00
02887dc164 fix static and profiling compilation and add profiling calculation 2020-05-07 14:09:58 +02:00
d048af11cd calculate correct collisions for classic in InsTrimLTO 2020-05-07 11:57:12 +02:00
0559d1d171 fix typos 2020-05-07 10:27:24 +02:00
37b681ac11 untracer README: one typo fixed 2020-05-07 10:09:08 +02:00
f065ddbdb2 Merge pull request #354 from jtpereyda/readme-apt-flex
add flex to apt install list
2020-05-07 09:31:00 +02:00
140053502b import transform fix into autodict, code-format 2020-05-07 08:08:20 +02:00
58fad91b0b add flex to apt install list 2020-05-06 16:00:23 -07:00
01b5aa123d better README for untracer 2020-05-06 17:20:42 +02:00
8cdf767bf5 doc update 2020-05-06 15:57:38 +02:00
e910882e32 fix untracer 2020-05-06 15:43:39 +02:00
a1c9c497d5 aarch64 support for afl-untracer 2020-05-06 15:37:49 +02:00
a63c838b10 make build options for qemu more visible 2020-05-06 14:16:19 +02:00
b7e574607c rename pass 2020-05-06 13:27:12 +02:00
10e6b4e454 fix STATIC compilation 2020-05-06 13:24:18 +02:00
ec5b1924c4 CTX+NGRAM != LTO 2020-05-06 11:55:50 +02:00
80ddb484de added InsTrimLTO :-) 2020-05-06 11:51:28 +02:00
cafb2e540e Merge pull request #353 from AFLplusplus/dev
update llvm version in README
2020-05-06 01:04:37 +02:00
b4e3f22259 update llvm version in README 2020-05-06 01:04:13 +02:00
df52157834 Merge pull request #352 from AFLplusplus/dev
Pull to master because of crash in string compare transform
2020-05-06 00:58:13 +02:00
a13958b32b updated unicornafl 2020-05-05 23:44:02 +02:00
a31b58eeea add one more alternative to python requirements: python-dev 2020-05-05 22:59:26 +02:00
e31b816aa0 fix unit tests when printf is a macro 2020-05-05 22:46:48 +02:00
0e5027d8d8 maybe_grow->ck_maybe_grow 2020-05-05 21:46:31 +02:00
dc79533191 more typos fixed 2020-05-05 20:29:40 +02:00
128e4d5565 more typos fixed 2020-05-05 20:23:16 +02:00
ad3960580d fixed typos 2020-05-05 20:19:04 +02:00
00683d06c2 fix LTO mode 2020-05-05 20:10:54 +02:00
a38980c80b unsized string compare fix 2020-05-05 17:57:56 +02:00
664a180d72 cleanup todo list 2020-05-05 15:39:15 +02:00
d6346561db ctx+ngram for instrim 2020-05-05 15:37:02 +02:00
d82ada89fe support older llvm versions 2020-05-05 14:08:24 +02:00
9d384b4e38 ctx and ngram fix 2020-05-05 12:46:49 +02:00
6e45e55d82 fix crash in AFL_LLVM_LAF_TRANSFORM_COMPARES 2020-05-05 10:38:44 +02:00
ecaccd9739 Merge pull request #351 from dpmdpm2/master
Fix typo in README.lto.md
2020-05-04 21:02:49 +02:00
95a2d49232 Fix typo in README.lto.md 2020-05-04 11:34:07 -07:00
16c16b3e6e ctx and ngram can be used together now 2020-05-04 18:01:47 +02:00
945e00b73f final touches for afl_network_proxy 2020-05-04 12:51:38 +02:00
e592b4bcf0 nw fixes 2020-05-04 10:37:45 +02:00
96ef2d3821 makefile fix 2020-05-04 10:24:29 +02:00
2d126dc750 Fix Unicorn support build script (#349)
* Fix Unicorn support build script for WSL.

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2020-05-04 10:14:49 +02:00
13a32e9595 fix makefile 2020-05-04 10:08:29 +02:00
73f7164048 add GNUmakefile 2020-05-04 09:53:59 +02:00
5b1b986c89 fix for afl-tmin -f 2020-05-03 14:19:03 +02:00
1c53bbea52 doubled the speed of afl_network_proxy 2020-05-03 14:09:32 +02:00
0c5c172a30 makefile fix 2020-05-02 12:57:33 +02:00
ff1643d81f todo update 2020-05-02 00:43:33 +02:00
378573ab8b AFL_LLVM_SKIP_NEVERZERO added 2020-05-02 00:39:13 +02:00
33ddf6ea0e add ghidra script and workaround ghidra/linux/ida weirdness 2020-05-01 17:07:44 +02:00
a2bc3538f7 python no longer needed for build 2020-05-01 12:03:41 +02:00
636e98d151 Merge remote-tracking branch 'origin/master' into dev 2020-05-01 02:13:24 +02:00
9f01737fa7 updated unicorn 2020-05-01 02:08:04 +02:00
be4e5d2617 minor sample things 2020-05-01 02:07:35 +02:00
cc78fb721b code format 2020-05-01 01:11:54 +02:00
bb7d2a7347 Merge pull request #345 from devnexen/afl_untracer_libs_display
afl-untracer little change to display libraries mapping on FreeBSD.
2020-05-01 01:03:53 +02:00
9d03763d94 at some point we have to do a rewrite of llvm_mode/GNUmakefile 2020-05-01 00:57:20 +02:00
3cf4529f3c afl-untracer little change to display libraries mapping on FreeBSD. 2020-04-30 23:01:46 +01:00
477fb58311 Merge pull request #344 from devnexen/afl_untracer_fbsd
afl-untracer raw freebsd support.
2020-04-30 23:38:01 +02:00
59043b24cc afl-untracer raw freebsd support. 2020-04-30 21:31:37 +01:00
15547eb654 fix send child status 2020-04-30 21:17:13 +02:00
16f9cc7369 afl-network-client fix 2020-04-30 21:13:45 +02:00
efa9df24c2 afl-untracer completed 2020-04-30 17:59:59 +02:00
a37eca9df5 afl-untracer - next step 2020-04-30 16:27:31 +02:00
e68d2345d5 test.sh: continue after failed test case qemu persistent mode 2020-04-29 22:25:10 +02:00
fced3e00ce wip: afl-untracer 2020-04-29 20:44:30 +02:00
c53663c7ac afl-proxy -> afl_proxy 2020-04-29 15:21:51 +02:00
bc2e65e482 added afl_network_proxy 2020-04-29 15:18:03 +02:00
ce2814967d add readme for afl-proxy 2020-04-29 02:56:51 +02:00
781725aeaf added afl-proxy to examples 2020-04-29 02:54:57 +02:00
9276dc9e6c fix #329 2020-04-28 10:55:22 +02:00
c7de368dc2 Merge pull request #342 from AFLplusplus/dev
fix for afl-showmap with -Q
2020-04-27 22:12:56 +02:00
fbd9994f6f better fix for showmap 2020-04-27 22:11:58 +02:00
087c368242 better fix for showmap 2020-04-27 22:10:08 +02:00
a56354a893 fix for afl-showmap with -Q 2020-04-27 19:30:32 +02:00
a5d4c8d532 Merge pull request #340 from AFLplusplus/dev
dev -> master
2020-04-27 12:12:43 +02:00
a46fe3ad43 fix for older llvm versions 2020-04-27 06:51:45 +02:00
4ffa5b0636 fix negative stability bug (hopefully) 2020-04-26 18:42:42 +02:00
62ec52dd95 Merge pull request #336 from AFLplusplus/dev
pull again ...
2020-04-26 16:51:21 +02:00
ea876e59a8 moved defines to type 2020-04-26 14:45:00 +02:00
66eee34709 refactored global lists 2020-04-26 02:32:09 +02:00
85627516a4 map_size one liner 2020-04-26 02:05:17 +02:00
b26ee09f71 minor fixes 2020-04-26 01:59:38 +02:00
fb89b042f8 Merge pull request #337 from devnexen/android_support_arc4_api
Android supports arc4 api.
2020-04-26 01:25:39 +02:00
646aeb2b18 try unicorn build without -j 2020-04-26 00:54:02 +02:00
2a60ceb694 fix issue #333 2020-04-25 21:29:19 +02:00
80916a3613 Android supports arc4 api. 2020-04-25 20:17:10 +01:00
0c3d06c41e refactored whitelist and blacklist in llvm_mode 2020-04-25 17:53:38 +02:00
07db922024 add to changelog 2020-04-25 13:09:27 +02:00
fa610270ab remove empty line 2020-04-25 13:08:42 +02:00
cefefba244 Merge branch 'master' into dev 2020-04-25 13:05:25 +02:00
42017bbeda fix python detection for Ubuntu and others 2020-04-25 12:57:45 +02:00
a3ee281e2b fix python detection for Ubuntu and others 2020-04-25 12:55:01 +02:00
232290108e only build afl-gcc-fast if afl-gcc-pass could be build 2020-04-25 12:51:14 +02:00
5c017d7071 travis Dockerfiles for testing and debugging 2020-04-25 12:48:48 +02:00
62aacf88ab fix simple names 2020-04-24 23:26:38 +02:00
b3e77d3d50 update documentation 2020-04-24 13:56:04 +02:00
766085293d variable map size fix, error reporting through forkserver, code format 2020-04-24 12:09:25 +02:00
4a593d0405 Merge pull request #331 from Mindavi/feature/fail-on-invalid-binary-name
afl-gcc and afl-clang: fail when binary name can't be used to determine build mode
2020-04-24 10:32:00 +02:00
82b6b8c87e afl-gcc and afl-clang: fail when binary name can't be used to determine build mode
This is a continuation of PR #318.
The goal is to prevent issues where binaries with the wrong name will
silently pass control to the C compiler instead of failing.
This makes it more explicit that aflplusplus relies on the name of the
binary for correct compiler execution.
2020-04-23 23:21:38 +02:00
b6f9f4c436 minor changes 2020-04-23 16:08:36 +02:00
b120ca27f8 add documentation for LTO fixed map address feature 2020-04-23 12:20:58 +02:00
5eb1f3a4c6 use mmap in llvm_mode if LTO is enabled 2020-04-23 12:02:15 +02:00
8ada9d06e8 fix make clean error 2020-04-23 11:51:32 +02:00
cce8c4dbae fixed map location support for LTO 2020-04-23 08:56:06 +02:00
3502db1ac5 more sanitizer functions for blacklist 2020-04-23 07:28:25 +02:00
df8a0e8418 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-04-22 13:51:40 +02:00
b8a25063f6 fix sed errors in afl_shm_init when using mmap 2020-04-22 13:51:36 +02:00
6df21f3489 GNUmakefile/unit tests: suppress compilation commandline output 2020-04-22 08:40:04 +02:00
dcba2c3642 test.sh: custom mutator test; make it compilable with available instrumenting
compiler
2020-04-22 08:02:46 +02:00
059c963467 unicornafl build script: fix prerequisite search for setuptools 2020-04-21 23:15:25 +02:00
ce9c6df456 libdislocator android build fix. (#327)
Fix function signature for bionic libc
2020-04-21 13:14:34 +02:00
0aef3b4040 add NULL check to malloc_usable_size 2020-04-21 13:14:34 +02:00
4cc0589440 unicornafl updated 2020-04-21 13:14:34 +02:00
96722083d8 add line 2020-04-21 13:14:34 +02:00
ee238eb00d Move comment about adding 8 bytes to buffer length to the line where we
actually add 8 bytes
Remove defunct TODO for posix_memalign as the function now exists
Add wrapper for malloc_usable_size
2020-04-21 13:14:34 +02:00
45ccc7d475 script to update uc refs; new unicornafl version 2020-04-21 13:14:34 +02:00
a32d2ad193 removed done todo 2020-04-21 13:14:34 +02:00
f25919ad56 dont error on git reset 2020-04-21 13:14:34 +02:00
ae524d856d clang warning fixed 2020-04-21 13:14:34 +02:00
9be4f9c055 code format 2020-04-21 13:14:34 +02:00
40e5b285f2 updated unicorn 2020-04-21 13:14:34 +02:00
3ca787ba76 wording 2020-04-21 13:14:34 +02:00
137b9ecf5e double include removed 2020-04-21 13:14:34 +02:00
2509624add android ashmem fix 2020-04-21 13:14:34 +02:00
8c6fcd98be reset git on deepclean 2020-04-21 13:14:34 +02:00
7dc825dbe9 typo 2020-04-21 13:14:34 +02:00
6b3336d107 switched to clang-format-10 2020-04-21 13:14:34 +02:00
ceeb266273 clean and deepclean Makefile updates 2020-04-21 13:14:34 +02:00
9bb0733eb5 clang-tidy readability-braces (#323) 2020-04-21 13:14:34 +02:00
22cdad2d20 make clean removes unicornafl dir if not in git 2020-04-21 13:14:34 +02:00
8b3befea6d update documentation 2020-04-21 13:14:34 +02:00
5b9928f1a9 fix some gcc dependencies and build problems on debian 32-Bit,
adapted qemu_mode AFL_ENTRYPOINT test case for 32 bit
2020-04-21 13:14:34 +02:00
856a59901e no need to rm folder 2020-04-21 13:14:34 +02:00
19d0961020 clean doesn't fail without unicornafl 2020-04-21 13:14:34 +02:00
3bd5e65edc clean no longer deletes unicornafl folder 2020-04-21 13:14:34 +02:00
b520046ab6 fix submodule 2020-04-21 13:14:34 +02:00
d22550a520 git for travis? 2020-04-21 13:14:34 +02:00
6f994ec56b fix compilation on Debian 32-bit (thanks to Marc) 2020-04-21 13:14:34 +02:00
09c8e40363 better detection of intel cpu on 32-bit Linux 2020-04-21 13:14:34 +02:00
8e44c06a13 fix docs typos 2020-04-21 13:14:34 +02:00
358f17f615 small portability fix (32-bit) for warning (size_t %lu -> %zu) 2020-04-21 13:14:34 +02:00
b109e31722 submodule path changed 2020-04-21 13:14:34 +02:00
b77458ae81 unicornafl updaetd 2020-04-21 13:14:34 +02:00
cfeb8e83f7 latest unicornafl 2020-04-21 13:14:34 +02:00
0fa9ad46ae added version 2020-04-21 13:14:34 +02:00
cfb11177cd submodule 2020-04-21 13:14:34 +02:00
0a1979fd20 examples Makefiles: silence errors when there is no 32-bit support installed 2020-04-21 13:14:34 +02:00
0dc64b93d8 v2.64d init 2020-04-21 13:14:34 +02:00
f6c9acd518 libdislocator android build fix. (#327)
Fix function signature for bionic libc
2020-04-21 10:17:11 +02:00
68218dd31c Merge pull request #326 from dpmdpm2/master
Add malloc_usable_size to libdislocator.so
2020-04-21 00:07:33 +02:00
441b64b467 add NULL check to malloc_usable_size 2020-04-20 15:00:48 -07:00
8b319969f3 unicornafl updated 2020-04-20 23:49:12 +02:00
41b1787565 add line 2020-04-20 23:27:09 +02:00
e6fccdd9c1 Move comment about adding 8 bytes to buffer length to the line where we
actually add 8 bytes
Remove defunct TODO for posix_memalign as the function now exists
Add wrapper for malloc_usable_size
2020-04-20 14:24:47 -07:00
0ffef8c79d script to update uc refs; new unicornafl version 2020-04-20 23:11:11 +02:00
3d52079a7c removed done todo 2020-04-20 22:18:39 +02:00
e47c29e728 dont error on git reset 2020-04-20 22:14:41 +02:00
280374f739 clang warning fixed 2020-04-20 22:07:47 +02:00
ce15937717 code format 2020-04-20 21:54:55 +02:00
c8f2ba5b49 updated unicorn 2020-04-20 21:40:34 +02:00
3dbfd18f36 wording 2020-04-20 21:18:32 +02:00
4be0ae2008 double include removed 2020-04-20 21:06:16 +02:00
67b39050df android ashmem fix 2020-04-20 21:05:02 +02:00
4ccd8c1400 reset git on deepclean 2020-04-20 21:03:06 +02:00
4f997665f1 typo 2020-04-20 16:10:06 +02:00
b6a15d9719 switched to clang-format-10 2020-04-20 11:32:44 +02:00
e90194093e Revert "fix compilation use CFLAGS_FLTO for afl-gotcpu also (thanks Marc)"
This reverts commit b408fdffcc.
2020-04-20 07:58:48 +02:00
4c90293e44 clean and deepclean Makefile updates 2020-04-19 16:48:42 +02:00
8197e9b2e4 clang-tidy readability-braces (#323) 2020-04-19 16:42:40 +02:00
baec99079f make clean removes unicornafl dir if not in git 2020-04-19 12:30:58 +02:00
16a5e6bf16 update documentation 2020-04-19 10:15:28 +02:00
39f715982d Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-04-19 00:38:57 +02:00
724d4ec3de fix some gcc dependencies and build problems on debian 32-Bit,
adapted qemu_mode AFL_ENTRYPOINT test case for 32 bit
2020-04-19 00:37:23 +02:00
e4670d3abc no need to rm folder 2020-04-18 23:16:00 +02:00
8aa86d063a clean doesn't fail without unicornafl 2020-04-18 22:33:56 +02:00
c1d9e00044 clean no longer deletes unicornafl folder 2020-04-18 22:31:21 +02:00
0827a447d3 fix submodule 2020-04-18 22:10:30 +02:00
2874565b36 git for travis? 2020-04-18 21:28:35 +02:00
8ed3126f28 fix compilation on Debian 32-bit (thanks to Marc) 2020-04-18 20:07:12 +02:00
b408fdffcc fix compilation use CFLAGS_FLTO for afl-gotcpu also (thanks Marc) 2020-04-18 19:54:54 +02:00
d9cd600c1b better detection of intel cpu on 32-bit Linux 2020-04-18 18:39:03 +02:00
68f18923ab fix docs typos 2020-04-18 11:32:06 +02:00
9e74a7dfe1 small portability fix (32-bit) for warning (size_t %lu -> %zu) 2020-04-18 10:48:24 +02:00
0b5b888f82 submodule path changed 2020-04-17 21:52:57 +02:00
46854b439a unicornafl updaetd 2020-04-17 21:44:33 +02:00
8ffed4b859 latest unicornafl 2020-04-17 21:43:55 +02:00
3b8cd9652a added version 2020-04-17 21:43:55 +02:00
269050aee3 submodule 2020-04-17 21:43:55 +02:00
6e753f8f0f examples Makefiles: silence errors when there is no 32-bit support installed 2020-04-17 19:42:03 +02:00
9adcc73d61 v2.64d init 2020-04-17 19:39:32 +02:00
ddea300822 Merge pull request #321 from AFLplusplus/dev
Push for next release
2020-04-17 19:25:34 +02:00
9900c92ebc locked to unicornafl version 2020-04-17 16:28:22 +02:00
0bd1264faf headers for clang-tidy 2020-04-17 14:30:36 +02:00
49753eb2d0 unused var 2020-04-17 14:27:28 +02:00
c9605f2251 ++2.64c 2020-04-17 14:10:18 +02:00
6ee11c2a6f little more speed for queue analysis 2020-04-17 14:08:40 +02:00
ef1d384184 add missing limits.h include for PATH_MAX (OpenBSD) 2020-04-17 13:45:22 +02:00
a6d4f04019 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-04-17 13:30:12 +02:00
87d27b8616 add AFL_NO_PYTHON to list of env variables 2020-04-17 13:29:32 +02:00
f22d8120ef fix afl-showmap for PATH_MAX on *BSD 2020-04-17 13:22:39 +02:00
8ecfbcdf34 removed tmp alloc in queue 2020-04-17 13:15:24 +02:00
263daaacaf remove static from tmp var in qemu 2020-04-17 12:04:16 +02:00
d3254d8066 llvm fix 2020-04-17 12:00:28 +02:00
76e15a0695 refactoring getting the map size 2020-04-17 11:56:08 +02:00
1931838a11 remove unnecessary map_size variables 2020-04-17 11:39:38 +02:00
6bd49b1d5c final fix for map_size 2020-04-17 11:24:40 +02:00
2d4d16755c merged upstream 2020-04-17 11:20:09 +02:00
bfcf6db17a fixes 2020-04-17 11:18:04 +02:00
bda4d8812e forgot MAP_SIZE for afl struct maps 2020-04-17 11:15:04 +02:00
f70d4a6fd4 added bugfix infos 2020-04-17 11:07:03 +02:00
90ff345d73 Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-04-17 11:01:20 +02:00
8fa5d4c313 clearer code 2020-04-17 11:01:14 +02:00
2162fd8e1a preliminary stuff for AFL_MAP_SIZE and afl-llvm-pass 2020-04-17 10:46:35 +02:00
248a2f2f0b added AFL_MAP_SIZE to env help output 2020-04-17 10:21:41 +02:00
ef311ec70c done implementing AFL_MAP_SIZE 2020-04-17 10:08:56 +02:00
5b70d23211 added AFL_MAP_SIZE (wip) 2020-04-17 09:10:49 +02:00
16ce555845 fixed 2 unimportant leaks 2020-04-17 07:52:21 +02:00
c961925356 fix plot_data output and code-format 2020-04-17 07:10:42 +02:00
23ea727915 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-04-16 19:53:51 +02:00
f157bca548 fix missing out_fd for cmplog forkserver 2020-04-16 19:53:42 +02:00
35937e6263 leak? 2020-04-16 19:33:40 +02:00
69bd7c16eb silence some clang warnings 2020-04-16 19:15:14 +02:00
6940e13629 removed redundent funcs 2020-04-16 17:50:08 +02:00
380ff114e9 the least radamsa 2020-04-16 16:51:23 +02:00
5e53002303 less radamsa 2020-04-16 16:48:40 +02:00
872d1c1d98 less radamsa 2020-04-16 16:47:53 +02:00
94187837c7 removed unused functions 2020-04-16 16:37:33 +02:00
ede3545d8b missing-decls reremoved 2020-04-16 16:25:02 +02:00
cdac882834 untitest decl 2020-04-16 16:09:52 +02:00
1ee224652c libradamsa fix 2020-04-16 16:05:39 +02:00
8511638afb hunting non-static functions 2020-04-16 15:38:43 +02:00
b10007a7b5 renamed duplicated func names 2020-04-16 15:32:04 +02:00
19ce862810 decoupled run and classify 2020-04-16 15:21:34 +02:00
124665b392 code-format 2020-04-16 14:47:08 +02:00
b420ccdbf8 fixed timeout flag to u32 2020-04-16 14:42:38 +02:00
5e8f385705 revert test.sh changes 2020-04-16 13:24:16 +02:00
dcc889a264 fix travis for cmpcov 2020-04-16 13:11:44 +02:00
f3789801f2 little has_new_bits improvement 2020-04-16 12:09:33 +02:00
0f08b13fa0 somewhat unified write_to_testcase 2020-04-15 23:22:23 +02:00
2ce6e7a7fb fix laf-intel transform disable 2020-04-15 23:01:33 +02:00
83d5864203 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-04-15 22:29:54 +02:00
7e2c52f2b9 disable compare-transform-pass when lto_mode and autodictionary is used. 2020-04-15 22:27:32 +02:00
e88f364282 add new github security writeup 2020-04-15 22:27:20 +02:00
21f696f02e fix document mode 2020-04-15 22:26:30 +02:00
ef1ea07e68 wrong bytes set 2020-04-15 20:22:32 +02:00
0c02a8f4d3 changed run_target 2020-04-15 19:23:26 +02:00
48f7f7a17b afl-clang-fast: fail when binary name can't be used to determine build mode (#318) 2020-04-15 12:08:33 +02:00
115ee8bad5 fix Makefile for examples/argv_fuzzing and socket_fuzzing 2020-04-14 21:19:03 +02:00
c009896c34 code format 2020-04-14 19:29:18 +02:00
6dc36f1e6e unified forkservered run_target, fixes #308 2020-04-14 19:27:25 +02:00
f4436f118c fixed #317 2020-04-14 17:21:15 +02:00
8440aaea5a Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-04-14 13:02:53 +02:00
0d0338012b one byte cmp in cmplog 2020-04-14 13:02:49 +02:00
5ac1b6e940 status 0 initialized 2020-04-14 13:01:54 +02:00
92aaaef381 code format 2020-04-14 12:42:38 +02:00
2c87e68ad6 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-04-14 12:40:03 +02:00
26e690c220 cmplog loop detection 2020-04-14 12:39:29 +02:00
b63dd7a464 NO_PYTHON documented 2020-04-14 12:07:46 +02:00
d2a7628748 fix travis fails 2020-04-14 11:26:07 +02:00
b1e7b834ac add missing default names for AFL_LLVM_INSTRUMENT 2020-04-14 11:24:53 +02:00
9eb47a924a UR -> rand_below 2020-04-14 10:42:29 +02:00
1d62bf1c37 solve conflicts 2020-04-14 10:12:41 +02:00
982d46e7cb solve conflicts 2020-04-14 10:11:22 +02:00
1fbface656 cmplog is now better 2020-04-14 10:09:03 +02:00
1374e65401 no more waitpid warning 2020-04-13 20:39:52 +02:00
0fab4e1955 c files static 2020-04-13 20:23:24 +02:00
a2574169e2 added NO_PYTHON support 2020-04-13 17:44:48 +02:00
4b88e059ef more robust search for clang for afl-clang-fast 2020-04-13 17:05:43 +02:00
12a7059ae8 added ignore info 2020-04-13 16:58:35 +02:00
a897f355a9 code format 2020-04-13 16:57:41 +02:00
326ab632c3 fixed uaf and warnings 2020-04-13 16:57:19 +02:00
dda096da03 allow -L -1 to enable mopt in parallel to classic mutation 2020-04-13 12:12:27 +02:00
5daec436f9 fix bug forksever fail not detected when using read_timed 2020-04-13 11:43:34 +02:00
033c743a41 fix all cmplog errors 2020-04-13 11:37:48 +02:00
459d8f9ba2 qemu cmplog test.sh 2020-04-13 10:53:37 +02:00
0022cc4782 fix some cmplog refactoring bugs 2020-04-13 10:40:24 +02:00
995e556065 cmplog forkserver tidying 2020-04-13 08:54:59 +02:00
a93268acec update todo 2020-04-12 22:45:54 +02:00
e70c54547e remove warnings with llvm11 2020-04-12 17:23:41 +02:00
7919545499 Better solution for ARM64 build fix (#315) 2020-04-12 16:55:52 +02:00
5a8db5954c update test.sh to new compcov features 2020-04-12 14:38:47 +02:00
ee4e1936d0 build on arm64 fix. tested on Android. (#313) 2020-04-12 14:20:10 +02:00
ec67780854 fix 32/64 bit LTO 2020-04-12 14:04:17 +02:00
aaf8835cdb updated changelog 2020-04-12 12:18:06 +02:00
0a525f768b local/global var for compare-transform-pass and code-format 2020-04-12 12:13:01 +02:00
4ed43b7632 m32/m64 support for LTO and code-format for test/ 2020-04-12 11:00:01 +02:00
5e09e13ece m32/m64 support for LTO and code-format for test/ 2020-04-12 10:58:58 +02:00
eec725a345 add global and local var support to autodictionary 2020-04-12 10:34:03 +02:00
fd63344ffc Fixed qbdi_mode/build.sh script (#311)
Co-authored-by: pyno <pyno@fearless>
2020-04-11 20:04:22 +02:00
90a9f22c3d fix #312 2020-04-11 18:31:46 +02:00
cc3ac932d9 fix -E/-V 2020-04-11 09:16:30 +02:00
d8947d1fa4 add extended forkserver feature to gcc_plugin and qemu_mode 2020-04-11 08:15:42 +02:00
32ba60185e more refactoring and update changelog 2020-04-11 08:02:54 +02:00
8bcfba8231 add missing file 2020-04-11 07:35:54 +02:00
68f269437d Autodictionary (#309)
* lto module clean-up

* step 1/3

* step 1/3 completed

* if tmp is ever made non-static

* parts 2 and 3 - autodictionary is complete

* variable map_size support

* variable map size: changed overlooked functions

* remove debug for autodict

* 64 bit alignment of map size

* fix review comments

* force 64 bit alignment on both sides

* typo

* better map transfer, display snapshot in UI

* update readme
2020-04-11 07:32:42 +02:00
29ee3a1ffc refactored cmplog 2020-04-11 01:09:07 +02:00
39e8b91806 code format 2020-04-10 22:54:31 +02:00
3ab7fcf5dd fixed fauxserver msg 2020-04-10 22:53:59 +02:00
3a509c6168 LTO optimization, variable map size, autodictionary (#307)
* lto module clean-up

* step 1/3

* step 1/3 completed

* if tmp is ever made non-static

* parts 2 and 3 - autodictionary is complete

* variable map_size support

* variable map size: changed overlooked functions

* remove debug for autodict

* 64 bit alignment of map size

* fix review comments

* force 64 bit alignment on both sides

* typo
2020-04-10 22:33:11 +02:00
6dcbc4dff4 void * types in allocs 2020-04-10 21:03:48 +02:00
d928b148d8 tackeled some warnings 2020-04-10 20:57:46 +02:00
3209a9d4e8 removed vla for tmpfile 2020-04-10 20:35:16 +02:00
f0f83bab52 resize fix + code format 2020-04-10 17:47:22 +02:00
6aa6af04ac files opened with fdopen should be closed with fclose 2020-04-10 16:45:45 +02:00
5b977453cb another mem leak fix for master/slave usage 2020-04-10 15:06:31 +02:00
a60e425d39 fix small memory leak for in_place_resume 2020-04-10 14:52:59 +02:00
4e3739cdf2 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-04-10 14:50:05 +02:00
e51b4700e2 Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-04-10 14:34:24 +02:00
0b9f7c4c89 added back afl_state_deinit 2020-04-10 14:34:17 +02:00
9dcdbbb649 README: minor additions and typo fixes 2020-04-10 12:07:21 +02:00
ac2f0c9896 remove GNU makefile variants 2020-04-10 11:44:43 +02:00
fbf5e08425 merge PR#306 from neoni (thanks), silence test when bash is not found 2020-04-09 18:11:39 +00:00
df5c264754 Merge branch 'dev' of github.com:aflplusplus/aflplusplus into dev 2020-04-09 16:27:07 +02:00
66f535ad61 check for empty AFL env vars 2020-04-09 16:27:00 +02:00
b8d84ababb lto module clean-up (#303) 2020-04-09 16:27:00 +02:00
b485b7a252 fix compilers for empty AFL_CC/AFL_CXX env 2020-04-09 16:27:00 +02:00
c1395bb543 LTO llvm11 (#302)
* new LTO mode for llvm 11

* remove unneeded afl-ld and env vars
2020-04-09 16:27:00 +02:00
0c2e998f69 2.63d init 2020-04-09 16:27:00 +02:00
504529c3aa fix crash triage example (#304) 2020-04-09 13:46:21 +02:00
1fab45024b check for empty AFL env vars 2020-04-09 13:17:56 +02:00
e354235ebb lto module clean-up (#303) 2020-04-09 13:13:07 +02:00
d55196352c fix compilers for empty AFL_CC/AFL_CXX env 2020-04-09 11:49:40 +02:00
45e569845e LTO llvm11 (#302)
* new LTO mode for llvm 11

* remove unneeded afl-ld and env vars
2020-04-09 10:36:28 +02:00
b55421d4a1 2.63d init 2020-04-09 10:30:24 +02:00
f06acc4e27 push new version 2020-04-09 09:14:12 +02:00
3c546341e3 fix indention 2020-04-09 09:08:04 +02:00
650bd1c179 Update README.snapshot.md 2020-04-09 08:58:35 +02:00
9efa96fe0c fixed critical whitespace 2020-04-09 01:40:03 +02:00
361c2ac576 fix compile for MacOSX -DFORTIFY_SOURCE=2 is problematic 2020-04-08 23:45:28 +02:00
54359be31a fix review comments by Heiko 2020-04-08 23:16:49 +02:00
77949acaee fix review comments by Heiko 2020-04-08 23:15:42 +02:00
88a852ef0f fix gcc_plugin Makefile (VPATH) 2020-04-08 22:21:32 +00:00
cb52b1757d Makefile cleanup 2020-04-08 21:39:11 +02:00
b4869d0663 unicorn_mode/samples/persistent Makefile portable version 2020-04-08 21:23:18 +02:00
30fa7b8006 remove todo 2020-04-08 19:17:21 +02:00
7793ca4055 fix travis - heiko test your changes on linux pls ;) 2020-04-08 18:28:35 +02:00
3353a23fcb one more include move 2020-04-08 18:19:38 +02:00
b32b9bd1d5 fix damage in test.sh 2020-04-08 18:16:08 +02:00
133a8cea1c llvm_mode ctx: move function terminator instrumentation before skipping blocks 2020-04-08 17:57:11 +02:00
729dbf7dda afl-fuzz: add usage info when no python support is there, use it in test.sh 2020-04-08 17:53:25 +00:00
67e9ef43a7 llvm_mode android fix 2020-04-08 17:22:31 +02:00
1b5b54fe94 fix limits.h include 2020-04-08 15:49:34 +02:00
9b3e6112ff Merge branch 'dev' of https://github.com/vanhauser-thc/AFLplusplus into dev 2020-04-08 17:39:19 +02:00
7663e7dd05 fix compilation in OpenBSD 2020-04-08 17:38:45 +02:00
2e29e64a3f Merge pull request #295 from devnexen/android_build_fix
Android build fix proposal.
2020-04-08 15:25:29 +02:00
15e0319c98 update todo 2020-04-08 13:12:14 +02:00
055ca98fb2 add missing piece for CTX coverage 2020-04-08 12:52:14 +02:00
968295ed81 added snapshot feature to documentation 2020-04-08 12:34:01 +02:00
48e366d7a8 argv_fuzzing Makefile: portable version 2020-04-08 10:44:42 +02:00
9aa10ef7ca fix travis 2020-04-08 10:39:32 +02:00
a85b8d69ef Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2020-04-08 10:21:46 +02:00
2900d51e5d socket_fuzzing Makefile: make it portable 2020-04-08 10:20:53 +02:00
63cc113f12 Merge pull request #298 from AFLplusplus/snapshot
Snapshot for LLVM mode in dev
2020-04-08 09:36:04 +02:00
3bf88da091 libdislocator: make Makefile portable 2020-04-08 08:50:30 +02:00
11e3122843 gcc_plugin: portable Makefile 2020-04-08 08:16:55 +02:00
dbe6b1da44 gcc_plugin fix compile for USEMMAP 2020-04-08 08:14:42 +02:00
91dc7776ec 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-08 04:57:01 +01:00
a5036499d2 update readme 2020-04-08 04:28:13 +02:00
9ef4b45609 ctx done 2020-04-08 03:56:12 +02:00
5b160f187d update env with AFL_NO_SNAPSHOT 2020-04-07 11:26:18 +02:00
604f17b897 small fixes 2020-04-07 10:56:31 +02:00
da1f3bf41e snapshot() in llvm mode 2020-04-07 10:50:21 +02:00
452acf3a75 added AFL_LLVM_INSTRUMENT, made USE_TRACE_PC obselete and llvm_mode Makefile fix, fixed for FUSELD (for LTO) 2020-04-06 13:33:49 +02:00
5ad50adaa8 GNUmakefile: python config add --ldflags, silence tests 2020-04-04 18:42:51 +02:00
c165165b58 unicorn_mode build script: find setuptools more reliably 2020-04-04 18:38:38 +02:00
0303d315fc Makefile bugfix macros are generally not expanded in shell calls 2020-04-04 16:45:59 +02:00
2129257454 fix silly error with uname -s 2020-04-04 16:16:13 +02:00
a7e9ce2e33 libtokencap, portable Makefile (for GNUmake and BSDmake) 2020-04-04 01:39:01 +02:00
b9851cdabe Merge branch 'dev' of https://github.com/vanhauser-thc/AFLplusplus into dev 2020-04-04 00:17:31 +02:00
a9261c6d64 portable version of Makefile (tested with bsdmake and GNUmake) 2020-04-04 00:15:08 +02:00
064131887b update todo 2020-04-03 14:17:31 +02:00
6b5d5b11b0 update todo 2020-04-03 14:00:29 +02:00
3f2859ec16 unit tests cleaning 2020-04-03 10:43:52 +02:00
5340f2f2eb code format, small improvements 2020-04-03 10:31:37 +02:00
8610b0e406 Merge branch 'dev' of github.com:vanhauser-thc/AFLplusplus into dev 2020-04-03 09:39:12 +02:00
ffb4767fc1 custom mutator readme 2020-04-03 09:39:09 +02:00
97cae2df99 no random timing for -s fixed_seed 2020-04-02 23:33:55 +02:00
dc0369eb10 fix make install regarding MANPAGES target 2020-04-02 22:14:39 +02:00
71f0bd003f Merge branch 'dev' of https://github.com/vanhauser-thc/AFLplusplus into dev 2020-04-02 17:00:58 +02:00
cc65e91eeb restore portable Makefiles 2020-04-02 17:00:35 +02:00
2ae0208d3b fix UI bug for bit flip yields 2020-04-02 16:46:31 +02:00
7114663f52 small enhancements and code-format 2020-04-02 16:41:33 +02:00
26e45e41ed remove MaybeAlign 2020-04-02 15:38:32 +02:00
38b14c5c44 fix make install 2020-04-02 15:18:05 +02:00
0c76d7e621 remove maybe_linking artifacts 2020-04-02 14:37:28 +02:00
c69c84da09 Merge pull request #288 from devnexen/llvm_mode_little_upd
llvm_mode: using MaybeAlign wrapper over the deprecated setter.
2020-04-02 10:55:58 +02:00
0565fe4213 rename all 'Makefile' to 'GNUmakefile', use -Werror for -flto checks 2020-04-02 12:24:39 +02:00
cb0bc98576 better asan 2020-04-02 02:44:49 +02:00
ef4eeede86 el no longer has to be used in loop 2020-04-01 20:42:50 +02:00
1cce581ffe fix unit test case for long list 2020-04-01 20:37:13 +02:00
989a85bb05 makefile asan fix 2020-04-01 18:56:59 +02:00
db3645c76b O3 again 2020-04-01 18:22:02 +02:00
b5c5496b2f list testcase added 2020-04-01 18:19:43 +02:00
4aec6dabde fixing unit tests (again) remove CFLAGS_FLTO, put LDFLAGS near the end 2020-04-01 16:18:44 +02:00
0fac7bd373 added (broken) list test 2020-04-01 15:56:27 +02:00
9c1c1062be added prealloc testcase 2020-04-01 15:56:27 +02:00
36a03e3bc8 add Make rule for new unit test 2020-04-01 15:51:34 +02:00
dfb0a65e07 fix make target unit test (tested on Ubuntu 16.04) 2020-04-01 15:39:36 +02:00
48655c2e12 llvm_mode: using MaybeAlign wrapper over the deprecated setter.
seems to be available even on LLVM 3.7
2020-03-31 19:25:24 +01:00
144 changed files with 12369 additions and 8044 deletions

View File

@ -10,7 +10,7 @@ AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
@ -72,7 +72,7 @@ IncludeCategories:
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentPPDirectives: BeforeHash
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave

View File

@ -29,14 +29,14 @@ CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
if CLANG_FORMAT_BIN is None:
o = 0
try:
p = subprocess.Popen(["clang-format-8", "--version"], stdout=subprocess.PIPE)
p = subprocess.Popen(["clang-format-10", "--version"], stdout=subprocess.PIPE)
o, _ = p.communicate()
o = str(o, "utf-8")
o = o[len("clang-format version "):].strip()
o = o[:o.find(".")]
o = int(o)
except:
print ("clang-format-8 is needed. Aborted.")
print ("clang-format-10 is needed. Aborted.")
exit(1)
#if o < 7:
# if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
@ -51,7 +51,7 @@ if CLANG_FORMAT_BIN is None:
# print ("clang-format 7 or above is needed. Aborted.")
# exit(1)
else:
CLANG_FORMAT_BIN = 'clang-format-8'
CLANG_FORMAT_BIN = 'clang-format-10'
COLUMN_LIMIT = 80
for line in fmt.split("\n"):
@ -70,8 +70,8 @@ def custom_format(filename):
out = ""
for line in src.split("\n"):
if line.startswith("#"):
if line.startswith("#define"):
if line.lstrip().startswith("#"):
if line[line.find("#")+1:].lstrip().startswith("define"):
in_define = True
if "/*" in line and not line.strip().startswith("/*") and line.endswith("*/") and len(line) < (COLUMN_LIMIT-2):

3
.gitignore vendored
View File

@ -42,10 +42,11 @@ qemu_mode/libcompcov/compcovtest
as
ld
qemu_mode/qemu-*
unicorn_mode/unicornafl/
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output/
core\.*
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_list
examples/afl_network_proxy/afl-network-server
examples/afl_network_proxy/afl-network-client

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "unicorn_mode/unicornafl"]
path = unicorn_mode/unicornafl
url = https://github.com/AFLplusplus/unicornafl.git

View File

@ -9,6 +9,9 @@ branches:
matrix:
include:
- os: linux
dist: focal
env: NAME="focal-amd64" MODERN="yes" GCC="9"
- os: linux
dist: bionic
env: NAME="bionic-amd64" MODERN="yes" GCC="7"
@ -32,7 +35,7 @@ jobs:
- arch: arm64
env:
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_STOP_MANUALLY=1
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_EXIT_WHEN_DONE=1
# TODO: test AFL_BENCH_UNTIL_CRASH once we have a target that crashes
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_BENCH_JUST_ONE=1
@ -41,8 +44,8 @@ before_install:
# export LLVM_DIR=${TRAVIS_BUILD_DIR}/${LLVM_PACKAGE}
- echo Testing on $NAME
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then wget "$LINK""$NAME".tar.xz ; export LLVM_CONFIG=`pwd`/"$NAME" ; tar xJf "$NAME".tar.xz ; fi
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y libtool libtool-bin automake bison libglib2.0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils 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
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y git libtool libtool-bin automake bison libglib2.0-0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev python3-setuptools ; fi
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y git libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils libcmocka-dev python3-setuptools ; fi
script:
- gcc -v

View File

@ -1,4 +1,4 @@
FROM ubuntu:eoan
FROM ubuntu
MAINTAINER David Carlier <devnexen@gmail.com>
LABEL "about"="AFLplusplus docker image"
RUN apt-get update && apt-get -y install \
@ -10,8 +10,10 @@ RUN apt-get update && apt-get -y install \
clang-9 \
flex \
git \
python3.7 \
python3.7-dev \
python3 \
python3-dev \
python3-setuptools \
python-is-python3 \
gcc-9 \
gcc-9-plugin-dev \
gcc-9-multilib \
@ -20,8 +22,6 @@ RUN apt-get update && apt-get -y install \
libtool-bin \
libglib2.0-dev \
llvm-9-dev \
python-setuptools \
python2.7-dev \
wget \
ca-certificates \
libpixman-1-dev \

View File

@ -52,14 +52,30 @@ 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
CFLAGS_OPT += -march=native
endif
# OS X does not like _FORTIFY_SOURCE=2
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
endif
ifdef STATIC
$(info Compiling static version of binaries)
# Disable python for static compilation to simplify things
PYTHON_OK=0
PYFLAGS=
CFLAGS_OPT += -static
LDFLAGS += -lm -lpthread -lz -lutil
endif
ifdef PROFILING
$(info Compiling with profiling information, for analysis: gprof ./afl-fuzz gmon.out > prof.txt)
CFLAGS_OPT += -pg -DPROFILING=1
LDFLAGS += -pg
endif
ifneq "$(shell uname -m)" "x86_64"
ifneq "$(shell uname -m)" "i386"
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
ifneq "$(shell uname -m)" "amd64"
ifneq "$(shell uname -m)" "i86pc"
AFL_NO_X86=1
@ -69,17 +85,27 @@ ifneq "$(shell uname -m)" "x86_64"
endif
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
override CFLAGS += -Wall -g -Wno-pointer-sign \
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
-I include/ -Werror -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
ifeq "$(shell uname -s)" "OpenBSD"
override CFLAGS += -I /usr/local/include/
LDFLAGS += -L /usr/local/lib/
endif
ifeq "$(shell uname -s)" "NetBSD"
override CFLAGS += -I /usr/pkg/include/
LDFLAGS += -L /usr/pkg/lib/
endif
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
ifneq "$(shell command -v python3m 2>/dev/null)" ""
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3m-config --includes)
PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
else
@ -88,24 +114,50 @@ ifneq "$(shell command -v python3m 2>/dev/null)" ""
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)
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3 2>/dev/null)" ""
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3-config --includes)
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
else
PYTHON_LIB ?= $(shell python3-config --ldflags)
endif
endif
endif
endif
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))
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python 2>/dev/null)" ""
ifneq "$(shell command -v python-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python-config --includes)
PYTHON_LIB ?= $(shell python-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
endif
endif
endif
# Old Ubuntu and others dont have python/python3-config so we hardcode 3.7
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3.7 2>/dev/null)" ""
ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
endif
endif
endif
# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1))
endif
endif
endif
@ -116,23 +168,23 @@ else
endif
ifneq "$(filter Linux GNU%,$(shell uname))" ""
LDFLAGS += -ldl
LDFLAGS += -ldl
endif
ifneq "$(findstring FreeBSD, $(shell uname))" ""
CFLAGS += -pthread
LDFLAGS += -lpthread
CFLAGS += -pthread
LDFLAGS += -lpthread
endif
ifneq "$(findstring NetBSD, $(shell uname))" ""
CFLAGS += -pthread
LDFLAGS += -lpthread
CFLAGS += -pthread
LDFLAGS += -lpthread
endif
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
TEST_CC = afl-gcc
TEST_CC = afl-gcc
else
TEST_CC = afl-clang
TEST_CC = afl-clang
endif
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
@ -145,18 +197,23 @@ else
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
ifdef NO_PYTHON
PYTHON_OK=0
PYFLAGS=
endif
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_LDFLAGS+=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
IN_REPO=0
ifeq "$(shell command -v git >/dev/null && git status >/dev/null 2>&1 && echo 1 || echo 0)" "1"
IN_REPO=1
endif
ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1 || echo 0)" "1"
IN_REPO=1
endif
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
endif
ifdef ASAN_BUILD
$(info Compiling ASAN version of binaries)
@ -164,12 +221,6 @@ ifdef ASAN_BUILD
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
@ -199,6 +250,7 @@ performance-test: source-only
@cd test ; ./test-performance.sh
# hint: make targets are also listed in the top level README.md
help:
@echo "HELP --- the following make targets exist:"
@echo "=========================================="
@ -208,10 +260,11 @@ help:
@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 "clean: cleans everything compiled (not downloads when on a checkout)"
@echo "deepclean: cleans everything including downloads"
@echo "code-format: format the code, do this before you commit and send a PR please!"
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
@echo "unit: perform unit tests (based on cmocka)"
@echo "unit: perform unit tests (based on cmocka and GNU linker)"
@echo "document: creates afl-fuzz-document which will only do one run and save all manipulated inputs into out/queue/mutations"
@echo "help: shows these build options :-)"
@echo "=========================================="
@ -266,7 +319,7 @@ test_python:
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"
@echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
endif
@ -298,19 +351,19 @@ src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.
$(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)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(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-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -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)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
# document all mutations and only do one run (use with only one input file!)
@ -318,34 +371,43 @@ document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
$(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
@$(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
@$(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
@$(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
@$(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
@$(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
@$(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
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_preallocable
unit_clean:
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
ifneq "$(shell uname)" "Darwin"
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean
else
unit:
@echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
endif
code-format:
./.custom-format.py -i src/*.c
./.custom-format.py -i include/*.h
@ -359,6 +421,7 @@ code-format:
./.custom-format.py -i gcc_plugin/*.cc
./.custom-format.py -i examples/*/*.c
./.custom-format.py -i examples/*/*.h
./.custom-format.py -i test/*.c
./.custom-format.py -i qemu_mode/patches/*.h
./.custom-format.py -i qemu_mode/libcompcov/*.c
./.custom-format.py -i qemu_mode/libcompcov/*.cc
@ -394,27 +457,40 @@ all_done: test_build
@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
.NOTPARALLEL: clean all
clean:
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 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 -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-*
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
-$(MAKE) -C llvm_mode clean
-$(MAKE) -C gcc_plugin clean
$(MAKE) -C libdislocator clean
$(MAKE) -C libtokencap clean
$(MAKE) -C examples/afl_network_proxy clean
$(MAKE) -C examples/socket_fuzzing clean
$(MAKE) -C examples/argv_fuzzing clean
$(MAKE) -C qemu_mode/unsigaction clean
$(MAKE) -C qemu_mode/libcompcov clean
$(MAKE) -C src/third_party/libradamsa/ clean
-rm -rf unicorn_mode/unicornafl
rm -rf qemu_mode/qemu-3.1.1
ifeq "$(IN_REPO)" "1"
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
else
rm -rf qemu_mode/qemu-3.1.1.tar.xz
rm -rf unicorn_mode/unicornafl
endif
deepclean: clean
rm -rf qemu_mode/qemu-3.1.1.tar.xz
rm -rf unicorn_mode/unicornafl
git reset --hard >/dev/null 2>&1 || true
distrib: all radamsa
-$(MAKE) -C llvm_mode
-$(MAKE) -C gcc_plugin
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
$(MAKE) -C examples/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing
cd qemu_mode && sh ./build_qemu_support.sh
@ -423,6 +499,7 @@ distrib: all radamsa
binary-only: all radamsa
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
$(MAKE) -C examples/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing
cd qemu_mode && sh ./build_qemu_support.sh
@ -433,6 +510,9 @@ source-only: all radamsa
-$(MAKE) -C gcc_plugin
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
#$(MAKE) -C examples/afl_network_proxy
#$(MAKE) -C examples/socket_fuzzing
#$(MAKE) -C examples/argv_fuzzing
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@ -468,6 +548,7 @@ install: all $(MANPAGES)
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi

View File

@ -1,2 +1,42 @@
all:
@echo please use GNU make, thanks!
@echo trying to use GNU make...
@gmake all
source-only:
@gmake source-only
binary-only:
@gmake binary-only
distrib:
@gmake distrib
man:
@gmake man
install:
@gmake install
document:
@gmake document
deepclean:
@gmake deepclean
code-format:
@gmake code-format
help:
@gmake help
tests:
@gmake tests
unit:
@gmake unit
unit_clean:
@gmake unit_clean
clean:
@gmake clean

View File

@ -4,9 +4,9 @@
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master)
Release Version: [2.63c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release Version: [2.65c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 2.63d
Github Version: 2.65d
includes all necessary/interesting changes from Google's afl 2.56b
@ -21,7 +21,7 @@
* Dominik Maier <mail@dmnk.co>.
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
it is unlikely to receive any notable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
## The enhancements compared to the original stock afl
@ -44,7 +44,7 @@
* Custom mutator by a library (instead of Python) by kyakdan
* Unicron mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
* Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
* LAF-Intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
@ -85,7 +85,7 @@
(3) partially via AFL_CODE_START/AFL_CODE_END
(4) Only for LLVM >= 9 and not all targets compile
(4) Only for LLVM >= 11 and not all targets compile
(5) upcoming, development in the branch
@ -124,9 +124,9 @@ However, we already work on so many things that we do not have the time for
all the big ideas.
This can be your way to support and contribute to AFL++ - extend it to
something cool
something cool.
We have an idea list in [docs/ideas.md](docs/ideas.md)
We have an idea list in [docs/ideas.md](docs/ideas.md).
For everyone who wants to contribute (and send pull requests) please read
[CONTRIBUTING.md](CONTRIBUTING.md) before your submit.
@ -137,7 +137,7 @@ 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 python-setuptools
$ sudo apt install build-essential libtool-bin python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools llvm
$ make distrib
$ sudo make install
```
@ -145,7 +145,7 @@ $ sudo make install
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
more. If you just want plain afl then do "make all", however compiling and
using at least llvm_mode is highly recommended for much better results -
hence in this case
hence in this case
```shell
$ make source-only
@ -158,8 +158,10 @@ These build targets exist:
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa
* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap, radamsa
* distrib: everything (for both binary-only and source code fuzzing)
* man: creates simple man pages from the help option of the programs
* install: installs everything you have compiled with the build options above
* clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well
* clean: cleans everything compiled, not downloads (unless not on a checkout)
* deepclean: cleans everything including downloads
* code-format: format the code, do this before you commit and send a PR please!
* tests: runs test cases to ensure that all features are still working as they should
* unit: perform unit tests (based on cmocka)
@ -177,6 +179,7 @@ These build options exist:
* STATIC - compile AFL++ static
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
* PROFILING - compile with profiling information (gprof)
* NO_PYTHON - disable python support
* AFL_NO_X86 - if compiling on non-intel/amd platforms
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
@ -184,7 +187,7 @@ e.g.: make ASAN_BUILD=1
Note that afl++ is faster and better the newer the compilers used are.
Hence gcc-9 and especially llvm-9 should be the compilers of choice.
Hence at least gcc-9 and especially llvm-9 should be the compilers of choice.
If your distribution does not have them, you can use the Dockerfile:
```shell
@ -350,6 +353,7 @@ Here are some good writeups to show how to effectively use AFL++:
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
If you are interested in fuzzing structured data (where you define what the
structure is), these two links have you covered:
@ -668,8 +672,9 @@ Here are some of the most important caveats for AFL:
To work around this, you can comment out the relevant checks (see
examples/libpng_no_checksum/ for inspiration); if this is not possible,
you can also write a postprocessor, as explained in
examples/post_library/ (with AFL_POST_LIBRARY)
you can also write a postprocessor, one of the hooks of custom mutators.
See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use
`AFL_CUSTOM_MUTATOR_LIBRARY`
- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
isn't due to any specific fault of afl-fuzz; see [docs/notes_for_asan.md](docs/notes_for_asan.md)

28
TODO.md
View File

@ -1,29 +1,22 @@
# TODO list for AFL++
## Roadmap 2.63
## Roadmap 2.65+
- complete custom_mutator API changes and documentation
- fix stability calculation bug
## Roadmap 2.64
- context sensitive branch coverage in llvm_mode
- sync_fuzzers(): only masters sync from all, slaves only sync from master
(@andrea: be careful, often people run all slaves)
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- random crc32 HASH_CONST per run? because with 65536 paths we have collisions
- namespace for targets? e.g. network
- libradamsa as a custom module?
- laf-intel build auto-dictionary?
- focal for travis
## Further down the road
afl-fuzz:
- sync_fuzzers(): only masters sync from all, slaves only sync from master
(@andrea: be careful, often people run all slaves)
- ascii_only mode for mutation output
- ascii_only mode for mutation output - or use a custom mutator for this?
- setting min_len/max_len/start_offset/end_offset limits for mutation output
llvm_mode:
- added context sensitive branch coverage
- add CT cov and ngram cov to LTO and InsTrim
- better whitelist solution for LTO
gcc_plugin:
@ -31,18 +24,11 @@ gcc_plugin:
- better instrumentation (seems to be better with gcc-9+)
qemu_mode:
- update to 4.x (probably this will be skipped :( )
- update to 5.x (if the performance bug if gone)
- 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?), 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.

View File

@ -9,6 +9,75 @@ Want to stay in the loop on major new features? Join our mailing list by
sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++2.65c (release):
- afl-fuzz:
- AFL_MAP_SIZE was not working correctly
- better python detection
- an old, old bug in afl that would show negative stability in rare
circumstances is now hopefully fixed
- AFL_POST_LIBRARY was deprecated, use AFL_CUSTOM_MUTATOR_LIBRARY
instead (see docs/custom_mutators.md)
- llvm_mode:
- afl-clang-fast/lto now do not skip single block functions. This
behaviour can be reactivated with AFL_LLVM_SKIPSINGLEBLOCK
- if LLVM 11 is installed the posix shm_open+mmap is used and a fixed
address for the shared memory map is used as this increases the
fuzzing speed
- InsTrim now has an LTO version! :-) That is the best and fastest mode!
- fixes to LTO mode if instrumented edges > MAP_SIZE
- CTX and NGRAM can now be used together
- CTX and NGRAM are now also supported in CFG/INSTRIM mode
- AFL_LLVM_LAF_TRANSFORM_COMPARES could crash, fixed
- added AFL_LLVM_SKIP_NEVERZERO to skip the never zero coverage counter
implementation. For targets with few or no loops or heavily called
functions. Gives a small performance boost.
- qemu_mode:
- add information on PIE/PIC load addresses for 32 bit
- better dependency checks
- gcc_plugin:
- better dependency checks
- unicorn_mode:
- validate_crash_callback can now count non-crashing inputs as crash as well
- better submodule handling
- afl-showmap: fix for -Q mode
- added examples/afl_network_proxy which allows to fuzz a target over the
network (not fuzzing tcp/ip services but running afl-fuzz on one system
and the target being on an embedded device)
- added examples/afl_untracer which does a binary-only fuzzing with the
modifications done in memory (intel32/64 and aarch64 support)
- added examples/afl_proxy which can be easily used to fuzz and instrument
non-standard things
- all:
- forkserver communication now also used for error reporting
- fix 32 bit build options
- make clean now leaves qemu-3.1.1.tar.xz and the unicornafl directory
intact if in a git/svn checkout - unless "deepclean" is used
### Version ++2.64c (release):
- llvm_mode LTO mode:
- now requires llvm11 - but compiles all targets! :)
- autodictionary feature added, enable with `AFL_LLVM_LTO_AUTODICTIONARY`
- variable map size usage
- afl-fuzz:
- variable map size support added (only LTO mode can use this)
- snapshot feature usage now visible in UI
- Now setting `-L -1` will enable MOpt in parallel to normal mutation.
Additionally, this allows to run dictionaries, radamsa and cmplog.
- fix for cmplog/redqueen mode if stdin was used
- fix for writing a better plot_data file
- qemu_mode: fix for persistent mode (which would not terminate or get stuck)
- compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also
static global and local variable comparisons (cannot find all though)
- extended forkserver: map_size and more information is communicated to
afl-fuzz (and afl-fuzz acts accordingly)
- new environment variable: AFL_MAP_SIZE to specify the size of the shared map
- if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed
(this bug is in vanilla afl too)
- added NO_PYTHON flag to disable python support when building afl-fuzz
- more refactoring
### Version ++2.63c (release):
! the repository was moved from vanhauser-thc to AFLplusplus. It is now
@ -41,7 +110,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
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
this mode is amazing but requires you to build llvm 11 yourself
- Added llvm_mode NGRAM prev_loc coverage by Adrean Herrera
(https://github.com/adrianherrera/afl-ngram-pass/), activate by setting
AFL_LLVM_INSTRUMENT=NGRAM-<value> or AFL_LLVM_NGRAM_SIZE=<value>
@ -117,7 +186,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- AFL_PERSISTENT_HOOK callback module for persistent QEMU
(see examples/qemu_persistent_hook)
- added qemu_mode/README.persistent.md documentation
- AFL_ENTRYPOINT noew has instruction granularity
- AFL_ENTRYPOINT now has instruction granularity
- afl-cmin is now a sh script (invoking awk) instead of bash for portability
the original script is still present as afl-cmin.bash
- afl-showmap: -i dir option now allows processing multiple inputs using the
@ -294,7 +363,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
you use the new -p option :-) - see docs/power_schedules.md
- added afl-system-config script to set all system performance options for fuzzing
- llvm_mode works with llvm 3.9 up to including 8 !
- qemu_mode got upgraded from 2.1 to 3.1 - incorporated from
- qemu_mode got upgraded from 2.1 to 3.1 - incorporated from
https://github.com/andreafioraldi/afl and with community patches added
@ -2508,3 +2577,6 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version 0.21b (2013-11-12):
- Initial public release.
- Added support for use of multiple custom mutators which can be specified using
the environment variable AFL_CUSTOM_MUTATOR_LIBRARY.

View File

@ -36,6 +36,9 @@ enter the pacemaker fuzzing mode.
Setting 0 will enter the pacemaker fuzzing mode at first, which is
recommended in a short time-scale evaluation.
Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in
parallel.
Other important parameters can be found in afl-fuzz.c, for instance,
'swarm_num': the number of the PSO swarms used in the fuzzing process.

View File

@ -1,682 +0,0 @@
# american fuzzy lop plus plus (afl++)
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master)
Release Version: 2.60c
Github Version: 2.60d
includes all necessary/interesting changes from Google's afl 2.56b
Originally developed by Michal "lcamtuf" Zalewski.
Repository: [https://github.com/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>.
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
## The enhancements compared to the original stock afl
Many improvements were made over the official afl release - which did not
get any feature improvements since November 2017.
Among other changes afl++ has a more performant llvm_mode, supports
llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU,
better *BSD and Android support and much, much more.
Additionally the following features and patches have been integrated:
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
* The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
* InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
* C. Holler's afl-fuzz Python mutator module and llvm_mode whitelist support: [https://github.com/choller/afl](https://github.com/choller/afl)
* Custom mutator by a library (instead of Python) by kyakdan
* unicorn_mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
* laf-intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
* Persistent mode and deferred forkserver for qemu_mode
* Win32 PE binary-only fuzzing with QEMU and Wine
* Radamsa mutator (enable with `-R` to add or `-RR` to run it exclusivly).
* qbdi_mode: fuzz android native libraries via QBDI framework
A more thorough list is available in the PATCHES file.
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
| ----------------------- |:-------:|:---------:|:----------:|:---------:|:------------:|
| laf-intel / CompCov | | x | | x86/arm | x86/arm |
| NeverZero | x | x(1) | (2) | x | x |
| Persistent mode | | x | x | x86 | x |
| Whitelist | | x | x | | |
| InsTrim | | x | | | |
neverZero:
(1) only in LLVM >= 9.0 due to a bug in llvm in previous versions
(2) gcc creates non-performant code, hence it is disabled in gcc_plugin
So all in all this is the best-of afl that is currently out there :-)
For new versions and additional information, check out:
[https://github.com/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>.
See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to
read this file.
## 0) Building and installing afl++
afl++ has many build options.
The easiest is to build and install everything:
```shell
$ make distrib
$ sudo make install
```
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
more. If you just want plain afl then do "make all", however compiling and
using at least llvm_mode is highly recommended for much better results -
hence in this case
```shell
$ make source-only
```
is what you should choose.
These build options exist:
* all: just the main afl++ binaries
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa
* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap, radamsa
* distrib: everything (for both binary-only and source code fuzzing)
* install: installs everything you have compiled with the build options above
* clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well
* code-format: format the code, do this before you commit and send a PR please!
* tests: runs test cases to ensure that all features are still working as they should
* help: shows these build options
[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html) you can also build statically linked versions of the
afl++ binaries by passing the STATIC=1 argument to make:
```shell
$ make all STATIC=1
```
Note that afl++ is faster and better the newer the compilers used are.
Hence gcc-9 and especially llvm-9 should be the compilers of choice.
If your distribution does not have them, you can use the Dockerfile:
```shell
$ docker build -t aflplusplus
```
## 1) Challenges of guided fuzzing
Fuzzing is one of the most powerful and proven strategies for identifying
security issues in real-world software; it is responsible for the vast
majority of remote code execution and privilege escalation bugs found to date
in security-critical software.
Unfortunately, fuzzing is also relatively shallow; blind, random mutations
make it very unlikely to reach certain code paths in the tested code, leaving
some vulnerabilities firmly outside the reach of this technique.
There have been numerous attempts to solve this problem. One of the early
approaches - pioneered by Tavis Ormandy - is corpus distillation. The method
relies on coverage signals to select a subset of interesting seeds from a
massive, high-quality corpus of candidate files, and then fuzz them by
traditional means. The approach works exceptionally well, but requires such
a corpus to be readily available. In addition, block coverage measurements
provide only a very simplistic understanding of program state, and are less
useful for guiding the fuzzing effort in the long haul.
Other, more sophisticated research has focused on techniques such as program
flow analysis ("concolic execution"), symbolic execution, or static analysis.
All these methods are extremely promising in experimental settings, but tend
to suffer from reliability and performance problems in practical uses - and
currently do not offer a viable alternative to "dumb" fuzzing techniques.
## 2) The afl-fuzz approach
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
form of edge coverage to effortlessly pick up subtle, local-scale changes to
program control flow.
Simplifying a bit, the overall algorithm can be summed up as:
1) Load user-supplied initial test cases into the queue,
2) Take next input file from the queue,
3) Attempt to trim the test case to the smallest size that doesn't alter
the measured behavior of the program,
4) Repeatedly mutate the file using a balanced and well-researched variety
of traditional fuzzing strategies,
5) If any of the generated mutations resulted in a new state transition
recorded by the instrumentation, add mutated output as a new entry in the
queue.
6) Go to 2.
The discovered test cases are also periodically culled to eliminate ones that
have been obsoleted by newer, higher-coverage finds; and undergo several other
instrumentation-driven effort minimization steps.
As a side result of the fuzzing process, the tool creates a small,
self-contained corpus of interesting test cases. These are extremely useful
for seeding other, labor- or resource-intensive testing regimes - for example,
for stress-testing browsers, office applications, graphics suites, or
closed-source tools.
The fuzzer is thoroughly tested to deliver out-of-the-box performance far
superior to blind fuzzing or coverage-only tools.
## 3) Instrumenting programs for use with AFL
PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
instead of afl-gcc/afl-g++ is much faster and has a few cool features.
See llvm_mode/ - however few code does not compile with llvm.
We support llvm versions 3.8.0 to 11.
When source code is available, instrumentation can be injected by a companion
tool that works as a drop-in replacement for gcc or clang in any standard build
process for third-party code.
The instrumentation has a fairly modest performance impact; in conjunction with
other optimizations implemented by afl-fuzz, most programs can be fuzzed as fast
or even faster than possible with traditional tools.
The correct way to recompile the target program may vary depending on the
specifics of the build process, but a nearly-universal approach would be:
```shell
$ CC=/path/to/afl/afl-gcc ./configure
$ make clean all
```
For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.
The clang wrappers (afl-clang and afl-clang++) can be used in the same way;
clang users may also opt to leverage a higher-performance instrumentation mode,
as described in [llvm_mode/README.md](llvm_mode/README.md).
Clang/LLVM has a much better performance and works with LLVM version 3.8.0 to 11.
Using the LAF Intel performance enhancements are also recommended, see
[llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md)
Using partial instrumentation is also recommended, see
[llvm_mode/README.whitelist.md](llvm_mode/README.whitelist.md)
When testing libraries, you need to find or write a simple program that reads
data from stdin or from a file and passes it to the tested library. In such a
case, it is essential to link this executable against a static version of the
instrumented library, or to make sure that the correct .so file is loaded at
runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static
build, usually possible via:
```shell
$ CC=/path/to/afl/afl-gcc ./configure --disable-shared
```
Setting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to
automatically enable code hardening options that make it easier to detect
simple memory bugs. Libdislocator, a helper library included with AFL (see
[libdislocator/README.md](libdislocator/README.md)) can help uncover heap corruption issues, too.
PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md)
file for important caveats.
## 4) Instrumenting binary-only apps
When source code is *NOT* available, the fuzzer offers experimental support for
fast, on-the-fly instrumentation of black-box binaries. This is accomplished
with a version of QEMU running in the lesser-known "user space emulation" mode.
QEMU is a project separate from AFL, but you can conveniently build the
feature by doing:
```shell
$ cd qemu_mode
$ ./build_qemu_support.sh
```
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
The mode is approximately 2-5x slower than compile-time instrumentation, is
less conducive to parallelization, and may have some other quirks.
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
your binary, then you can use afl-fuzz normally and it will have twice
the speed compared to qemu_mode.
A more comprehensive description of these and other options can be found in
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
## 5) Power schedules
The power schedules were copied from Marcel Böhme's excellent AFLfast
implementation and expand on the ability to discover new paths and
therefore may increase the code coverage.
The available schedules are:
- explore (default)
- fast
- coe
- quad
- lin
- exploit
In parallel mode (-M/-S, several instances with shared queue), we suggest to
run the master using the exploit schedule (-p exploit) and the slaves with a
combination of cut-off-exponential (-p coe), exponential (-p fast; default),
and explore (-p explore) schedules.
In single mode, using -p fast is usually more beneficial than the default
explore mode.
(We don't want to change the default behaviour of afl, so "fast" has not been
made the default mode).
More details can be found in the paper published at the 23rd ACM Conference on
Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
## 6) Choosing initial test cases
To operate correctly, the fuzzer requires one or more starting file that
contains a good example of the input data normally expected by the targeted
application. There are two basic rules:
- Keep the files small. Under 1 kB is ideal, although not strictly necessary.
For a discussion of why size matters, see [perf_tips.md](docs/perf_tips.md).
- Use multiple test cases only if they are functionally different from
each other. There is no point in using fifty different vacation photos
to fuzz an image library.
You can find many good examples of starting files in the testcases/ subdirectory
that comes with this tool.
PS. If a large corpus of data is available for screening, you may want to use
the afl-cmin utility to identify a subset of functionally distinct files that
exercise different code paths in the target binary.
## 7) Fuzzing binaries
The fuzzing process itself is carried out by the afl-fuzz utility. This program
requires a read-only directory with initial test cases, a separate place to
store its findings, plus a path to the binary to test.
For target binaries that accept input directly from stdin, the usual syntax is:
```shell
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
```
For programs that take input from a file, use '@@' to mark the location in
the target's command line where the input file name should be placed. The
fuzzer will substitute this for you:
```shell
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
```
You can also use the -f option to have the mutated data written to a specific
file. This is useful if the program expects a particular file extension or so.
Non-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command
line) or in a traditional, blind-fuzzer mode (specify -n).
You can use -t and -m to override the default timeout and memory limit for the
executed process; rare examples of targets that may need these settings touched
include compilers and video decoders.
Tips for optimizing fuzzing performance are discussed in [perf_tips.md](docs/perf_tips.md).
Note that afl-fuzz starts by performing an array of deterministic fuzzing
steps, which can take several days, but tend to produce neat test cases. If you
want quick & dirty results right away - akin to zzuf and other traditional
fuzzers - add the -d option to the command line.
## 8) Interpreting output
See the [docs/status_screen.md](docs/status_screen.md) file for information on
how to interpret the displayed stats and monitor the health of the process. Be
sure to consult this file especially if any UI elements are highlighted in red.
The fuzzing process will continue until you press Ctrl-C. At minimum, you want
to allow the fuzzer to complete one queue cycle, which may take anywhere from a
couple of hours to a week or so.
There are three subdirectories created within the output directory and updated
in real time:
- queue/ - test cases for every distinctive execution path, plus all the
starting files given by the user. This is the synthesized corpus
mentioned in section 2.
Before using this corpus for any other purposes, you can shrink
it to a smaller size using the afl-cmin tool. The tool will find
a smaller subset of files offering equivalent edge coverage.
- crashes/ - unique test cases that cause the tested program to receive a
fatal signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are
grouped by the received signal.
- hangs/ - unique test cases that cause the tested program to time out. The
default time limit before something is classified as a hang is
the larger of 1 second and the value of the -t parameter.
The value can be fine-tuned by setting AFL_HANG_TMOUT, but this
is rarely necessary.
Crashes and hangs are considered "unique" if the associated execution paths
involve any state transitions not seen in previously-recorded faults. If a
single bug can be reached in multiple ways, there will be some count inflation
early in the process, but this should quickly taper off.
The file names for crashes and hangs are correlated with parent, non-faulting
queue entries. This should help with debugging.
When you can't reproduce a crash found by afl-fuzz, the most likely cause is
that you are not setting the same memory limit as used by the tool. Try:
```shell
$ LIMIT_MB=50
$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )
```
Change LIMIT_MB to match the -m parameter passed to afl-fuzz. On OpenBSD,
also change -Sv to -Sd.
Any existing output directory can be also used to resume aborted jobs; try:
```shell
$ ./afl-fuzz -i- -o existing_output_dir [...etc...]
```
If you have gnuplot installed, you can also generate some pretty graphs for any
active fuzzing task using afl-plot. For an example of how this looks like,
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
## 9) Parallelized fuzzing
Every instance of afl-fuzz takes up roughly one core. This means that on
multi-core systems, parallelization is necessary to fully utilize the hardware.
For tips on how to fuzz a common target on multiple cores or multiple networked
machines, please refer to [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md).
The parallel fuzzing mode also offers a simple way for interfacing AFL to other
fuzzers, to symbolic or concolic execution engines, and so forth; again, see the
last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips.
## 10) Fuzzer dictionaries
By default, afl-fuzz mutation engine is optimized for compact data formats -
say, images, multimedia, compressed data, regular expression syntax, or shell
scripts. It is somewhat less suited for languages with particularly verbose and
redundant verbiage - notably including HTML, SQL, or JavaScript.
To avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to
seed the fuzzing process with an optional dictionary of language keywords,
magic headers, or other special tokens associated with the targeted data type
-- and use that to reconstruct the underlying grammar on the go:
[http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)
To use this feature, you first need to create a dictionary in one of the two
formats discussed in [dictionaries/README.md](dictionaries/README.md);
and then point the fuzzer to it via the -x option in the command line.
(Several common dictionaries are already provided in that subdirectory, too.)
There is no way to provide more structured descriptions of the underlying
syntax, but the fuzzer will likely figure out some of this based on the
instrumentation feedback alone. This actually works in practice, say:
[http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)
PS. Even when no explicit dictionary is given, afl-fuzz will try to extract
existing syntax tokens in the input corpus by watching the instrumentation
very closely during deterministic byte flips. This works for some types of
parsers and grammars, but isn't nearly as good as the -x mode.
If a dictionary is really hard to come by, another option is to let AFL run
for a while, and then use the token capture library that comes as a companion
utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md).
## 11) Crash triage
The coverage-based grouping of crashes usually produces a small data set that
can be quickly triaged manually or with a very simple GDB or Valgrind script.
Every crash is also traceable to its parent non-crashing test case in the
queue, making it easier to diagnose faults.
Having said that, it's important to acknowledge that some fuzzing crashes can be
difficult to quickly evaluate for exploitability without a lot of debugging and
code analysis work. To assist with this task, afl-fuzz supports a very unique
"crash exploration" mode enabled with the -C flag.
In this mode, the fuzzer takes one or more crashing test cases as the input,
and uses its feedback-driven fuzzing strategies to very quickly enumerate all
code paths that can be reached in the program while keeping it in the
crashing state.
Mutations that do not result in a crash are rejected; so are any changes that
do not affect the execution path.
The output is a small corpus of files that can be very rapidly examined to see
what degree of control the attacker has over the faulting address, or whether
it is possible to get past an initial out-of-bounds read - and see what lies
beneath.
Oh, one more thing: for test case minimization, give afl-tmin a try. The tool
can be operated in a very simple way:
```shell
$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
```
The tool works with crashing and non-crashing test cases alike. In the crash
mode, it will happily accept instrumented and non-instrumented binaries. In the
non-crashing mode, the minimizer relies on standard AFL instrumentation to make
the file simpler without altering the execution path.
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
afl-fuzz.
Another recent addition to AFL is the afl-analyze tool. It takes an input
file, attempts to sequentially flip bytes, and observes the behavior of the
tested program. It then color-codes the input based on which sections appear to
be critical, and which are not; while not bulletproof, it can often offer quick
insights into complex file formats. More info about its operation can be found
near the end of [docs/technical_details.md](docs/technical_details.md).
## 12) Going beyond crashes
Fuzzing is a wonderful and underutilized technique for discovering non-crashing
design and implementation errors, too. Quite a few interesting bugs have been
found by modifying the target programs to call abort() when, say:
- Two bignum libraries produce different outputs when given the same
fuzzer-generated input,
- An image library produces different outputs when asked to decode the same
input image several times in a row,
- A serialization / deserialization library fails to produce stable outputs
when iteratively serializing and deserializing fuzzer-supplied data,
- A compression library produces an output inconsistent with the input file
when asked to compress and then decompress a particular blob.
Implementing these or similar sanity checks usually takes very little time;
if you are the maintainer of a particular package, you can make this code
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).
## 13) Common-sense risks
Please keep in mind that, similarly to many other computationally-intensive
tasks, fuzzing may put strain on your hardware and on the OS. In particular:
- Your CPU will run hot and will need adequate cooling. In most cases, if
cooling is insufficient or stops working properly, CPU speeds will be
automatically throttled. That said, especially when fuzzing on less
suitable hardware (laptops, smartphones, etc), it's not entirely impossible
for something to blow up.
- Targeted programs may end up erratically grabbing gigabytes of memory or
filling up disk space with junk files. AFL tries to enforce basic memory
limits, but can't prevent each and every possible mishap. The bottom line
is that you shouldn't be fuzzing on systems where the prospect of data loss
is not an acceptable risk.
- Fuzzing involves billions of reads and writes to the filesystem. On modern
systems, this will be usually heavily cached, resulting in fairly modest
"physical" I/O - but there are many factors that may alter this equation.
It is your responsibility to monitor for potential trouble; with very heavy
I/O, the lifespan of many HDDs and SSDs may be reduced.
A good way to monitor disk I/O on Linux is the 'iostat' command:
```shell
$ iostat -d 3 -x -k [...optional disk ID...]
```
## 14) Known limitations & areas for improvement
Here are some of the most important caveats for AFL:
- AFL detects faults by checking for the first spawned process dying due to
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
these signals may need to have the relevant code commented out. In the same
vein, faults in child processed spawned by the fuzzed target may evade
detection unless you manually add some code to catch that.
- As with any other brute-force tool, the fuzzer offers limited coverage if
encryption, checksums, cryptographic signatures, or compression are used to
wholly wrap the actual data format to be tested.
To work around this, you can comment out the relevant checks (see
examples/libpng_no_checksum/ for inspiration); if this is not possible,
you can also write a postprocessor, as explained in
examples/post_library/ (with AFL_POST_LIBRARY)
- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
isn't due to any specific fault of afl-fuzz; see [docs/notes_for_asan.md](docs/notes_for_asan.md)
for tips.
- There is no direct support for fuzzing network services, background
daemons, or interactive apps that require UI interaction to work. You may
need to make simple code changes to make them behave in a more traditional
way. Preeny may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
Some useful tips for modifying network-based services can be also found at:
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
- AFL doesn't output human-readable coverage data. If you want to monitor
coverage, use afl-cov from Michael Rash: [https://github.com/mrash/afl-cov](https://github.com/mrash/afl-cov)
- Occasionally, sentient machines rise against their creators. If this
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
Beyond this, see INSTALL for platform-specific tips.
## 15) Special thanks
Many of the improvements to the original afl and afl++ wouldn't be possible
without feedback, bug reports, or patches from:
```
Jann Horn Hanno Boeck
Felix Groebert Jakub Wilk
Richard W. M. Jones Alexander Cherepanov
Tom Ritter Hovik Manucharyan
Sebastian Roschke Eberhard Mattes
Padraig Brady Ben Laurie
@dronesec Luca Barbato
Tobias Ospelt Thomas Jarosch
Martin Carpenter Mudge Zatko
Joe Zbiciak Ryan Govostes
Michael Rash William Robinet
Jonathan Gray Filipe Cabecinhas
Nico Weber Jodie Cunningham
Andrew Griffiths Parker Thompson
Jonathan Neuschaefer Tyler Nighswander
Ben Nagy Samir Aguiar
Aidan Thornton Aleksandar Nikolich
Sam Hakim Laszlo Szekeres
David A. Wheeler Turo Lamminen
Andreas Stieger Richard Godbee
Louis Dassy teor2345
Alex Moneger Dmitry Vyukov
Keegan McAllister Kostya Serebryany
Richo Healey Martijn Bogaard
rc0r Jonathan Foote
Christian Holler Dominique Pelle
Jacek Wielemborek Leo Barnes
Jeremy Barnes Jeff Trull
Guillaume Endignoux ilovezfs
Daniel Godas-Lopez Franjo Ivancic
Austin Seipp Daniel Komaromy
Daniel Binderman Jonathan Metzman
Vegard Nossum Jan Kneschke
Kurt Roeckx Marcel Boehme
Van-Thuan Pham Abhik Roychoudhury
Joshua J. Drake Toby Hutton
Rene Freingruber Sergey Davidoff
Sami Liedes Craig Young
Andrzej Jackowski Daniel Hodson
Nathan Voss Dominik Maier
Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu
```
Thank you!
## 16) Contact
Questions? Concerns? Bug reports? The contributors can be reached via
[https://github.com/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
archives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users)

1
docs/README.md Symbolic link
View File

@ -0,0 +1 @@
../README.md

View File

@ -16,6 +16,10 @@ fuzzing by using libraries that perform mutations according to a given grammar.
The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY`
or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function.
Now afl also supports multiple custom mutators which can be specified in the same `AFL_CUSTOM_MUTATOR_LIBRARY` environment variable like this.
```bash
export AFL_CUSTOM_MUTATOR_LIBRARY="full/path/to/mutator_first.so;full/path/to/mutator_second.so"
```
Please see [APIs](#2-apis) and [Usage](#3-usage) for detail.
The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage).
@ -29,13 +33,14 @@ 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);
size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf);
int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size);
size_t afl_custom_trim(void *data, uint8_t **out_buf);
int32_t afl_custom_post_trim(void *data, int success) {
size_t afl_custom_havoc_mutation(void *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t max_size);
uint8_t afl_custom_havoc_mutation_probability(void *data);
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename); void afl_custom_queue_new_entry(void *data, const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue);
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);
```
@ -47,7 +52,7 @@ def init(seed):
def fuzz(buf, add_buf, max_size):
return mutated_out
def pre_save(buf):
def post_process(buf):
return out_buf
def init_trim(buf):
@ -80,13 +85,16 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
- `queue_get` (optional):
This method determines whether the fuzzer should fuzz the current queue
entry or not
This method determines whether the custom fuzzer should fuzz the current
queue entry or not
- `fuzz` (required):
- `fuzz` (optional):
This method performs custom mutations on a given input. It also accepts an
additional test case.
Note that this function is optional - but it makes sense to use it.
You would only skip this if `post_process` is used to fix checksums etc.
so you are using it e.g. as a post processing library.
- `havoc_mutation` and `havoc_mutation_probability` (optional):
@ -95,7 +103,7 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
`havoc_mutation_probability`, returns the probability that `havoc_mutation`
is called in havoc. By default, it is 6%.
- `pre_save` (optional):
- `post_process` (optional):
For some cases, the format of the mutated data returned from the custom
mutator is not suitable to directly execute the target with this input.
@ -103,13 +111,20 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
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
`post_process` function. This function is then transforming the data into the
format expected by the API before executing the target.
- `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue.
- `deinit`:
The last method to be called, deinitializing the state.
Note that there are also three functions for trimming as described in the
next section.
### Trimming Support
The generic trimming routines implemented in AFL++ can easily destroy the
@ -156,10 +171,8 @@ trimmed input. Here's a quick API description:
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.
Omitting any of three trimming methods will cause the trimming to be disabled
and trigger a fallback to the builtin default trimming routine.
### Environment Variables
@ -209,12 +222,15 @@ For C/C++ mutator, the source code must be compiled as a shared object:
```bash
gcc -shared -Wall -O3 example.c -o example.so
```
Note that if you specify multiple custom mutators, the corresponding functions will
be called in the order in which they are specified. e.g first `post_process` function of
`example_first.so` will be called and then that of `example_second.so`
### Run
C/C++
```bash
export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so
export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so"
afl-fuzz /path/to/program
```

View File

@ -83,6 +83,10 @@ tools make fairly broad use of environmental variables:
The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset
of the settings discussed in section #1, with the exception of:
- Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting
functions with a single basic block. This is useful for most C and
some C++ targets. This works for all instrumentation modes.
- AFL_AS, since this toolchain does not directly invoke GNU as.
- TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are
@ -97,12 +101,15 @@ Then there are a few specific features that are only available in llvm_mode:
- AFL_LLVM_INSTRUMENT - this configures the instrumentation mode.
Available options:
DEFAULT - classic AFL (map[cur_loc ^ prev_loc >> 1]++)
CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default)
CFG - InsTrim instrumentation (see below)
LTO - LTO instrumentation (see below)
CTX - context sensitive instrumentation (see below)
NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
Only one can be used.
In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or
NGRAM, seperate the options with a comma "," then, e.g.:
AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4
Not that this is a good idea to use both CTX and NGRAM :)
### LTO
@ -111,13 +118,25 @@ Then there are a few specific features that are only available in llvm_mode:
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.
built if LLVM 11 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 ;-)
- AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
(recommended)
- AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target
binary based on string compare and memory compare functions.
afl-fuzz will automatically get these transmitted when starting to
fuzz.
None of the following options are necessary to be used and are rather for
manual use (which only ever the author of this LTO implementation will use).
These are used if several seperated instrumentation are performed which
are then later combined.
- AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than
the default 0x10000. A value of 0 or empty sets the map address to be
dynamic (the original afl way, which is slower)
- AFL_LLVM_MAP_DYNAMIC sets the shared memory address to be dynamic
- AFL_LLVM_LTO_STARTID sets the starting location ID for the instrumentation.
This defaults to 1
- AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written
@ -127,7 +146,13 @@ Then there are a few specific features that are only available in llvm_mode:
### INSTRIM
This feature increases the speed by ~15% without any disadvantages.
This feature increases the speed by ~15% without any disadvantages to the
classic instrumentation.
Note that there is also an LTO version (if you have llvm 11 or higher) -
that is the best instrumentation we have. Use `afl-clang-lto` to activate.
The InsTrim LTO version additionally has all the options and features of
LTO (see above).
- Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode
@ -135,10 +160,6 @@ Then there are a few specific features that are only available in llvm_mode:
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
@ -195,6 +216,10 @@ Then there are a few specific features that are only available in llvm_mode:
slowdown due a performance issue that is only fixed in llvm 9+.
This feature increases path discovery by a little bit.
- Setting AFL_LLVM_SKIP_NEVERZERO=1 will not implement the skip zero
test. If the target performs only few loops then this will give a
small performance boost.
See llvm_mode/README.neverzero.md
### CMPLOG
@ -238,6 +263,11 @@ checks or alter some of the more exotic semantics of the tool:
normally indicated by the cycle counter in the UI turning green. May be
convenient for some types of automated jobs.
- AFL_MAP_SIZE sets the size of the shared map that afl-fuzz, afl-showmap,
afl-tmin and afl-analyze create to gather instrumentation data from
the target. This must be equal or larger than the size the target was
compiled with.
- Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core
on Linux systems. This slows things down, but lets you run more instances
of afl-fuzz than would be prudent (if you really want to).
@ -280,9 +310,8 @@ checks or alter some of the more exotic semantics of the tool:
else. This makes the "own finds" counter in the UI more accurate.
Beyond counter aesthetics, not much else should change.
- Setting AFL_POST_LIBRARY allows you to configure a postprocessor for
mutated files - say, to fix up checksums. See examples/post_library/
for more.
- Note that AFL_POST_LIBRARY is deprecated, use AFL_CUSTOM_MUTATOR_LIBRARY
instead (see below).
- Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with
afl_custom_fuzz() creates additional mutations through this library.

View File

@ -56,13 +56,6 @@ functionality is now available as the "persistent" feature described in
http://llvm.org/docs/LibFuzzer.html
## AFL fixup shim (Ben Nagy)
Allows AFL_POST_LIBRARY postprocessors to be written in arbitrary languages
that don't have C / .so bindings. Includes examples in Go.
https://github.com/bnagy/aflfix
## TriforceAFL (Tim Newsham and Jesse Hertz)
Leverages QEMU full system emulation mode to allow AFL to target operating

View File

@ -0,0 +1,43 @@
PREFIX ?= /usr/local
BIN_PATH = $(PREFIX)/bin
DOC_PATH = $(PREFIX)/share/doc/afl
PROGRAMS = afl-network-client afl-network-server
HASH=\#
CFLAGS += -Wno-pointer-sign
ifdef STATIC
CFLAGS += -static
endif
ifeq "$(shell echo '$(HASH)include <libdeflate.h>@int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
CFLAGS += -DUSE_DEFLATE=1
LDFLAGS += -ldeflate
$(info libdeflate-dev was detected, using compression)
else
$(warn did not find libdeflate-dev, cannot use compression)
endif
all: $(PROGRAMS)
help:
@echo make options:
@echo STATIC - build as static binaries
@echo COMPRESS_TESTCASES - compress test cases
afl-network-client: afl-network-client.c
$(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS)
afl-network-server: afl-network-server.c
$(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS)
clean:
rm -f $(PROGRAMS) *~ core
install: all
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH)
install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH)
install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md

View File

@ -0,0 +1,2 @@
all:
@echo please use GNU make, thanks!

View File

@ -0,0 +1,61 @@
# afl-network-proxy
If you want to run afl-fuzz over the network than this is what you need :)
Note that the impact on fuzzing speed will be huge, expect a loss of 90%.
## When to use this
1. when you have to fuzz a target that has to run on a system that cannot
contain the fuzzing output (e.g. /tmp too small and file system is read-only)
2. when the target instantly reboots on crashes
3. ... any other reason you would need this
## how to get it running
### Compiling
Just type `make` and let the autodetection do everything for you.
Note that you will get a 40-50% performance increase if you have libdeflate-dev
installed. The GNUmakefile will autodetect it if present.
If your target has large test cases (10+kb) that are ascii only or large chunks
of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them.
For most targets this hurts performance though so it is disabled by default.
### on the target
Run `afl-network-server` with your target with the -m and -t values you need.
Important is the -i parameter which is the TCP port to listen on.
e.g.:
```
$ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@
```
### on the (afl-fuzz) master
Just run afl-fuzz with your normal options, however the target should be
`afl-network-client` with the IP and PORT of the `afl-network-server` and
increase the -t value:
```
$ afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111
```
Note the '+' on the -t parameter value. The afl-network-server will take
care of proper timeouts hence afl-fuzz should not. The '+' increases the
timeout and the value itself should be 500-1000 higher than the one on
afl-network-server.
### networking
The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to
either. Note that also the outgoing interface can be specified with a '%' for
`afl-network-client`, e.g. `fe80::1234%eth0`.
Also make sure your default TCP window size is larger than your MAP_SIZE
(130kb is a good value).
On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem`
## how to compile and install
`make && sudo make install`

View File

@ -0,0 +1,413 @@
/*
american fuzzy lop++ - afl-network-client
---------------------------------------
Written by Marc Heuse <mh@mh-sec.de>
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#ifdef USE_DEFLATE
#include <libdeflate.h>
#endif
u8 *__afl_area_ptr;
#ifdef __ANDROID__
u32 __afl_map_size = MAP_SIZE;
#else
__thread u32 __afl_map_size = MAP_SIZE;
#endif
/* Error reporting to forkserver controller */
void send_forkserver_error(int error) {
u32 status;
if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
}
/* SHM setup. */
static void __afl_map_shm(void) {
char *id_str = getenv(SHM_ENV_VAR);
char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
u32 val = atoi(ptr);
if (val > 0) __afl_map_size = val;
}
if (__afl_map_size > MAP_SIZE) {
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
fprintf(stderr,
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
fprintf(stderr,
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
}
}
if (id_str) {
#ifdef USEMMAP
const char * shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1);
}
/* map the shared memory segment to the address space of the process */
shm_base =
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED) {
close(shm_fd);
shm_fd = -1;
fprintf(stderr, "mmap() failed\n");
send_forkserver_error(FS_ERROR_MMAP);
exit(2);
}
__afl_area_ptr = shm_base;
#else
u32 shm_id = atoi(id_str);
__afl_area_ptr = shmat(shm_id, 0, 0);
#endif
if (__afl_area_ptr == (void *)-1) {
send_forkserver_error(FS_ERROR_SHMAT);
exit(1);
}
/* Write something into the bitmap so that the parent doesn't give up */
__afl_area_ptr[0] = 1;
}
}
/* Fork server logic. */
static void __afl_start_forkserver(void) {
u8 tmp[4] = {0, 0, 0, 0};
u32 status = 0;
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (status) status |= (FS_OPT_ENABLED);
memcpy(tmp, &status, 4);
/* Phone home and tell the parent that we're OK. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
}
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
s32 status, res = 0x0fffffff; // res is a dummy pid
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &status, 4) != 4) return 0;
/* we have a testcase - read it */
status = read(0, buf, max_len);
/* report that we are starting the target */
if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
if (status < 1)
return 0;
else
return status;
}
static void __afl_end_testcase(int status) {
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
}
/* you just need to modify the while() loop in this main() */
int main(int argc, char *argv[]) {
u8 * interface, *buf, *ptr;
s32 s = -1;
struct addrinfo hints, *hres, *aip;
u32 * lenptr, max_len = 65536;
#ifdef USE_DEFLATE
u8 * buf2;
u32 * lenptr1, *lenptr2, buf2_len, compress_len;
size_t decompress_len;
#endif
if (argc < 3 || argc > 4) {
printf("Syntax: %s host port [max-input-size]\n\n", argv[0]);
printf("Requires host and port of the remote afl-proxy-server instance.\n");
printf(
"IPv4 and IPv6 are supported, also binding to an interface with "
"\"%%\"\n");
printf("The max-input-size default is %u.\n", max_len);
printf(
"The default map size is %u and can be changed with setting "
"AFL_MAP_SIZE.\n",
__afl_map_size);
exit(-1);
}
if ((interface = index(argv[1], '%')) != NULL) *interface++ = 0;
if (argc > 3)
if ((max_len = atoi(argv[3])) < 0)
FATAL("max-input-size may not be negative or larger than 2GB: %s",
argv[3]);
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL)
if ((__afl_map_size = atoi(ptr)) < 8)
FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr);
if ((buf = malloc(max_len + 4)) == NULL)
PFATAL("can not allocate %u memory", max_len + 4);
lenptr = (u32 *)buf;
#ifdef USE_DEFLATE
buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size);
if ((buf2 = malloc(buf2_len + 8)) == NULL)
PFATAL("can not allocate %u memory", buf2_len + 8);
lenptr1 = (u32 *)buf2;
lenptr2 = (u32 *)(buf2 + 4);
#endif
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0)
PFATAL("could not resolve target %s", argv[1]);
for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) {
if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) {
#ifdef SO_BINDTODEVICE
if (interface != NULL)
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
strlen(interface) + 1) < 0)
fprintf(stderr, "Warning: could not bind to device %s\n", interface);
#else
fprintf(stderr,
"Warning: binding to interface is not supported for your OS\n");
#endif
#ifdef SO_PRIORITY
int priority = 7;
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
0) {
priority = 6;
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority,
sizeof(priority)) < 0)
WARNF("could not set priority on socket");
}
#endif
if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1;
}
}
#ifdef USE_DEFLATE
struct libdeflate_compressor *compressor;
compressor = libdeflate_alloc_compressor(1);
struct libdeflate_decompressor *decompressor;
decompressor = libdeflate_alloc_decompressor();
fprintf(stderr, "Compiled with compression support\n");
#endif
if (s == -1)
FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]);
else
fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]);
/* we initialize the shared memory map and start the forkserver */
__afl_map_shm();
__afl_start_forkserver();
int i = 1, j, status, ret, received;
// fprintf(stderr, "Waiting for first testcase\n");
while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) {
// fprintf(stderr, "Sending testcase with len %u\n", *lenptr);
#ifdef USE_DEFLATE
#ifdef COMPRESS_TESTCASES
// we only compress the testcase if it does not fit in the TCP packet
if (*lenptr > 1500 - 20 - 32 - 4) {
// set highest byte to signify compression
*lenptr1 = (*lenptr | 0xff000000);
*lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr,
buf2 + 8, buf2_len);
if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8)
PFATAL("sending test data failed");
// fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2);
// for (u32 i = 0; i < *lenptr; i++)
// fprintf(stderr, "%02x", buf[i + 4]);
// fprintf(stderr, "\n");
// for (u32 i = 0; i < *lenptr2; i++)
// fprintf(stderr, "%02x", buf2[i + 8]);
// fprintf(stderr, "\n");
} else {
#endif
#endif
if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4)
PFATAL("sending test data failed");
#ifdef USE_DEFLATE
#ifdef COMPRESS_TESTCASES
// fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr);
}
#endif
#endif
received = 0;
while (received < 4 &&
(ret = recv(s, &status + received, 4 - received, 0)) > 0)
received += ret;
if (received != 4)
FATAL("did not receive waitpid data (%d, %d)", received, ret);
// fprintf(stderr, "Received status\n");
received = 0;
#ifdef USE_DEFLATE
while (received < 4 &&
(ret = recv(s, &compress_len + received, 4 - received, 0)) > 0)
received += ret;
if (received != 4)
FATAL("did not receive compress_len (%d, %d)", received, ret);
// fprintf(stderr, "Received status\n");
received = 0;
while (received < compress_len &&
(ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0)
received += ret;
if (received != compress_len)
FATAL("did not receive coverage data (%d, %d)", received, ret);
if (libdeflate_deflate_decompress(decompressor, buf2, compress_len,
__afl_area_ptr, __afl_map_size,
&decompress_len) != LIBDEFLATE_SUCCESS ||
decompress_len != __afl_map_size)
FATAL("decompression failed");
// fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len);
// for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x",
// __afl_area_ptr[i]); fprintf(stderr, "\n");
#else
while (received < __afl_map_size &&
(ret = recv(s, __afl_area_ptr + received, __afl_map_size - received,
0)) > 0)
received += ret;
if (received != __afl_map_size)
FATAL("did not receive coverage data (%d, %d)", received, ret);
#endif
// fprintf(stderr, "Received coverage\n");
/* report the test case is done and wait for the next */
__afl_end_testcase(status);
// fprintf(stderr, "Waiting for next testcase %d\n", ++i);
}
#ifdef USE_DEFLATE
libdeflate_free_compressor(compressor);
libdeflate_free_decompressor(decompressor);
#endif
return 0;
}

View File

@ -0,0 +1,712 @@
/*
american fuzzy lop++ - network proxy server
-------------------------------------------
Originally written by Michal Zalewski
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com> and
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#define AFL_MAIN
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
#include "forkserver.h"
#include "sharedmem.h"
#include "common.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <netdb.h>
#ifdef USE_DEFLATE
#include <libdeflate.h>
struct libdeflate_compressor * compressor;
struct libdeflate_decompressor *decompressor;
#endif
static u8 *in_file, /* Minimizer input test case */
*out_file;
static u8 *in_data; /* Input data for trimming */
static u8 *buf2;
static s32 in_len;
static u32 map_size = MAP_SIZE;
static size_t buf2_len;
static volatile u8 stop_soon; /* Ctrl-C pressed? */
/* See if any bytes are set in the bitmap. */
static inline u8 anything_set(afl_forkserver_t *fsrv) {
u32 *ptr = (u32 *)fsrv->trace_bits;
u32 i = (map_size >> 2);
while (i--) {
if (*(ptr++)) { return 1; }
}
return 0;
}
static void at_exit_handler(void) {
afl_fsrv_killall();
}
/* Write output file. */
static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
s32 ret;
unlink(path); /* Ignore errors */
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
ck_write(ret, mem, len, path);
lseek(ret, 0, SEEK_SET);
return ret;
}
/* Execute target application. Returns 0 if the changes are a dud, or
1 if they should be kept. */
static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
u8 first_run) {
afl_fsrv_write_to_testcase(fsrv, mem, len);
fsrv_run_result_t ret =
afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); }
if (stop_soon) {
SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST);
exit(1);
}
return ret;
}
/* Handle Ctrl-C and the like. */
static void handle_stop_sig(int sig) {
stop_soon = 1;
afl_fsrv_killall();
}
/* Do basic preparations - persistent fds, filenames, etc. */
static void set_up_environment(afl_forkserver_t *fsrv) {
u8 *x;
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
if (!out_file) {
u8 *use_dir = ".";
if (access(use_dir, R_OK | W_OK | X_OK)) {
use_dir = get_afl_env("TMPDIR");
if (!use_dir) { use_dir = "/tmp"; }
}
out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid());
}
unlink(out_file);
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
/* Set sane defaults... */
x = get_afl_env("ASAN_OPTIONS");
if (x) {
if (!strstr(x, "abort_on_error=1")) {
FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
}
if (!strstr(x, "symbolize=0")) {
FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
}
}
x = get_afl_env("MSAN_OPTIONS");
if (x) {
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
MSAN_ERROR) " - please fix!");
}
if (!strstr(x, "symbolize=0")) {
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
}
}
setenv("ASAN_OPTIONS",
"abort_on_error=1:"
"detect_leaks=0:"
"symbolize=0:"
"allocator_may_return_null=1",
0);
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:"
"abort_on_error=1:"
"allocator_may_return_null=1:"
"msan_track_origins=0", 0);
if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) {
u8 *qemu_preload = getenv("QEMU_SET_ENV");
u8 *afl_preload = getenv("AFL_PRELOAD");
u8 *buf;
s32 i, afl_preload_size = strlen(afl_preload);
for (i = 0; i < afl_preload_size; ++i) {
if (afl_preload[i] == ',') {
PFATAL(
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
"specified!");
}
}
if (qemu_preload) {
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
qemu_preload, afl_preload, afl_preload);
} else {
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
afl_preload, afl_preload);
}
setenv("QEMU_SET_ENV", buf, 1);
ck_free(buf);
} else {
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
}
}
}
/* Setup signal handlers, duh. */
static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
sa.sa_flags = SA_RESTART;
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
/* Various ways of saying "stop". */
sa.sa_handler = handle_stop_sig;
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
}
/* Display usage hints. */
static void usage(u8 *argv0) {
SAYF(
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n"
" -i port - the port to listen for the client to connect to\n\n"
"Execution control settings:\n"
" -f file - input file read by the tested program (stdin)\n"
" -t msec - timeout for each run (%d ms)\n"
" -m megs - memory limit for child process (%d MB)\n"
" -Q - use binary-only instrumentation (QEMU mode)\n"
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
" -W - use qemu-based instrumentation with Wine (Wine "
"mode)\n\n"
"Environment variables used:\n"
"TMPDIR: directory to use for temporary input files\n"
"ASAN_OPTIONS: custom settings for ASAN\n"
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT);
exit(1);
}
int recv_testcase(int s, void **buf, size_t *max_len) {
u32 size;
s32 ret;
size_t received;
received = 0;
while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0)
received += ret;
if (received != 4) FATAL("did not receive size information");
if (size == 0) FATAL("did not receive valid size information");
// fprintf(stderr, "received size information of %d\n", size);
if ((size & 0xff000000) != 0xff000000) {
*buf = ck_maybe_grow(buf, max_len, size);
received = 0;
// fprintf(stderr, "unCOMPRESS (%u)\n", size);
while (received < size &&
(ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0)
received += ret;
} else {
#ifdef USE_DEFLATE
u32 clen;
size -= 0xff000000;
*buf = ck_maybe_grow(buf, max_len, size);
received = 0;
while (received < 4 &&
(ret = recv(s, &clen + received, 4 - received, 0)) > 0)
received += ret;
if (received != 4) FATAL("did not receive clen1 information");
// fprintf(stderr, "received clen information of %d\n", clen);
if (clen < 1)
FATAL("did not receive valid compressed len information: %u", clen);
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, clen);
received = 0;
while (received < clen &&
(ret = recv(s, buf2 + received, clen - received, 0)) > 0)
received += ret;
if (received != clen) FATAL("did not receive compressed information");
if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf,
*max_len,
&received) != LIBDEFLATE_SUCCESS)
FATAL("decompression failed");
// fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received);
// for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]);
// fprintf(stderr, "\n");
// for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x",
// ((u8*)(*buf))[i]); fprintf(stderr, "\n");
#else
FATAL("Received compressed data but not compiled with compression support");
#endif
}
// fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len);
if (received != size)
FATAL("did not receive testcase data %lu != %u, %d", received, size, ret);
// fprintf(stderr, "received testcase\n");
return size;
}
/* Main entry point */
int main(int argc, char **argv_orig, char **envp) {
s32 opt, s, sock, on = 1, port = -1;
size_t max_len = 0;
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
char **use_argv;
struct sockaddr_in6 serveraddr, clientaddr;
int addrlen = sizeof(clientaddr);
char str[INET6_ADDRSTRLEN];
char ** argv = argv_cpy_dup(argc, argv_orig);
u8 * send_buf;
#ifdef USE_DEFLATE
u32 *lenptr;
#endif
afl_forkserver_t fsrv_var = {0};
afl_forkserver_t *fsrv = &fsrv_var;
afl_fsrv_init(fsrv);
map_size = get_map_size();
fsrv->map_size = map_size;
if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc");
while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) {
switch (opt) {
case 'i':
if (port > 0) { FATAL("Multiple -i options not supported"); }
port = atoi(optarg);
if (port < 1 || port > 65535)
FATAL("invalid port definition, must be between 1-65535: %s", optarg);
break;
case 'f':
if (out_file) { FATAL("Multiple -f options not supported"); }
fsrv->use_stdin = 0;
out_file = optarg;
break;
case 'm': {
u8 suffix = 'M';
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
mem_limit_given = 1;
if (!optarg) { FATAL("Wrong usage of -m"); }
if (!strcmp(optarg, "none")) {
fsrv->mem_limit = 0;
break;
}
if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
optarg[0] == '-') {
FATAL("Bad syntax used for -m");
}
switch (suffix) {
case 'T':
fsrv->mem_limit *= 1024 * 1024;
break;
case 'G':
fsrv->mem_limit *= 1024;
break;
case 'k':
fsrv->mem_limit /= 1024;
break;
case 'M':
break;
default:
FATAL("Unsupported suffix or bad syntax for -m");
}
if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
FATAL("Value of -m out of range on 32-bit systems");
}
}
break;
case 't':
if (timeout_given) { FATAL("Multiple -t options not supported"); }
timeout_given = 1;
if (!optarg) { FATAL("Wrong usage of -t"); }
fsrv->exec_tmout = atoi(optarg);
if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
FATAL("Dangerously low value of -t");
}
break;
case 'Q':
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
fsrv->qemu_mode = 1;
break;
case 'U':
if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
unicorn_mode = 1;
break;
case 'W': /* Wine+QEMU mode */
if (use_wine) { FATAL("Multiple -W options not supported"); }
fsrv->qemu_mode = 1;
use_wine = 1;
if (!mem_limit_given) { fsrv->mem_limit = 0; }
break;
case 'h':
usage(argv[0]);
return -1;
break;
default:
usage(argv[0]);
}
}
if (optind == argc || port < 1) { usage(argv[0]); }
check_environment_vars(envp);
sharedmem_t shm = {0};
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
in_data = ck_maybe_grow((void **)&in_data, &max_len, 65536);
atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment(fsrv);
fsrv->target_path = find_binary(argv[optind]);
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
if (fsrv->qemu_mode) {
if (use_wine) {
use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
argv + optind);
} else {
use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
argv + optind);
}
} else {
use_argv = argv + optind;
}
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed");
#ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
WARNF("setsockopt(SO_REUSEADDR) failed");
}
#endif
#ifdef SO_PRIORITY
int priority = 7;
if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
0) {
priority = 6;
if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
0)
WARNF("could not set priority on socket");
}
#endif
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin6_family = AF_INET6;
serveraddr.sin6_port = htons(port);
serveraddr.sin6_addr = in6addr_any;
if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
PFATAL("bind() failed");
if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
afl_fsrv_start(fsrv, use_argv, &stop_soon,
get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
#ifdef USE_DEFLATE
compressor = libdeflate_alloc_compressor(1);
decompressor = libdeflate_alloc_decompressor();
buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, map_size + 16);
lenptr = (u32 *)(buf2 + 4);
fprintf(stderr, "Compiled with compression support\n");
#endif
fprintf(stderr,
"Waiting for incoming connection from afl-network-client on port %d "
"...\n",
port);
if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); }
fprintf(stderr, "Received connection, starting ...\n");
#ifdef SO_PRIORITY
priority = 7;
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) {
priority = 6;
if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
WARNF("could not set priority on socket");
}
#endif
while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) {
// fprintf(stderr, "received %u\n", in_len);
(void)run_target(fsrv, use_argv, in_data, in_len, 1);
memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size);
#ifdef USE_DEFLATE
memcpy(buf2, &fsrv->child_status, 4);
*lenptr = (u32)libdeflate_deflate_compress(
compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8);
// fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr);
// for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x",
// fsrv->trace_bits[i]); fprintf(stderr, "\n");
if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr)
FATAL("could not send data");
#else
memcpy(send_buf, &fsrv->child_status, 4);
if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size)
FATAL("could not send data");
#endif
// fprintf(stderr, "sent result\n");
}
unlink(out_file);
if (out_file) { ck_free(out_file); }
out_file = NULL;
afl_shm_deinit(&shm);
afl_fsrv_deinit(fsrv);
if (fsrv->target_path) { ck_free(fsrv->target_path); }
if (in_data) { ck_free(in_data); }
#if USE_DEFLATE
if (buf2) { ck_free(buf2); }
libdeflate_free_compressor(compressor);
libdeflate_free_decompressor(decompressor);
#endif
argv_cpy_free(argv);
exit(0);
}

View File

@ -0,0 +1,7 @@
all: afl-proxy
afl-proxy: afl-proxy.c
$(CC) -I../../include -o afl-proxy afl-proxy.c
clean:
rm -f afl-proxy *~ core

View File

@ -0,0 +1,9 @@
# afl-proxy
afl-proxy is an example skeleton file which can easily be used to fuzz
and instrument non-standard things.
You only need to change the while() loop of the main() to send the
data of buf[] with length len to the target and write the coverage
information to __afl_area_ptr[__afl_map_size]

View File

@ -0,0 +1,238 @@
/*
american fuzzy lop++ - afl-proxy skeleton example
---------------------------------------------------
Written by Marc Heuse <mh@mh-sec.de>
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
HOW-TO
======
You only need to change the while() loop of the main() to send the
data of buf[] with length len to the target and write the coverage
information to __afl_area_ptr[__afl_map_size]
*/
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
u8 *__afl_area_ptr;
#ifdef __ANDROID__
u32 __afl_map_size = MAP_SIZE;
#else
__thread u32 __afl_map_size = MAP_SIZE;
#endif
/* Error reporting to forkserver controller */
void send_forkserver_error(int error) {
u32 status;
if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
}
/* SHM setup. */
static void __afl_map_shm(void) {
char *id_str = getenv(SHM_ENV_VAR);
char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
u32 val = atoi(ptr);
if (val > 0) __afl_map_size = val;
}
if (__afl_map_size > MAP_SIZE) {
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
fprintf(stderr,
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
fprintf(stderr,
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
}
}
if (id_str) {
#ifdef USEMMAP
const char * shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1);
}
/* map the shared memory segment to the address space of the process */
shm_base =
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED) {
close(shm_fd);
shm_fd = -1;
fprintf(stderr, "mmap() failed\n");
send_forkserver_error(FS_ERROR_MMAP);
exit(2);
}
__afl_area_ptr = shm_base;
#else
u32 shm_id = atoi(id_str);
__afl_area_ptr = shmat(shm_id, 0, 0);
#endif
if (__afl_area_ptr == (void *)-1) {
send_forkserver_error(FS_ERROR_SHMAT);
exit(1);
}
/* Write something into the bitmap so that the parent doesn't give up */
__afl_area_ptr[0] = 1;
}
}
/* Fork server logic. */
static void __afl_start_forkserver(void) {
u8 tmp[4] = {0, 0, 0, 0};
u32 status = 0;
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (status) status |= (FS_OPT_ENABLED);
memcpy(tmp, &status, 4);
/* Phone home and tell the parent that we're OK. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
}
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
s32 status, res = 0xffffff;
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &status, 4) != 4) return 0;
/* we have a testcase - read it */
status = read(0, buf, max_len);
/* report that we are starting the target */
if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
if (status < 1)
return 0;
else
return status;
}
static void __afl_end_testcase(void) {
int status = 0xffffff;
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
}
/* you just need to modify the while() loop in this main() */
int main(int argc, char *argv[]) {
/* This is were the testcase data is written into */
u8 buf[1024]; // this is the maximum size for a test case! set it!
u32 len;
/* here you specify the map size you need that you are reporting to
afl-fuzz. */
__afl_map_size = MAP_SIZE; // default is 65536
/* then we initialize the shared memory map and start the forkserver */
__afl_map_shm();
__afl_start_forkserver();
while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
/* here you have to create the magic that feeds the buf/len to the
target and write the coverage to __afl_area_ptr */
// ... the magic ...
/* report the test case is done and wait for the next */
__afl_end_testcase();
}
return 0;
}

View File

@ -0,0 +1,16 @@
ifdef DEBUG
OPT=-O0
else
OPT=-O3
endif
all: afl-untracer libtestinstr.so
afl-untracer: afl-untracer.c
$(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl
libtestinstr.so: libtestinstr.c
$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
clean:
rm -f afl-untracer libtestinstr.so *~ core

View File

@ -0,0 +1,59 @@
# afl-untracer - fast fuzzing of binary-only libraries
## Introduction
afl-untracer is an example skeleton file which can easily be used to fuzz
a closed source library.
It requires less memory and is x3-5 faster than qemu_mode however it is way
more course grained and does not provide interesting features like compcov
or cmplog.
Supported is so far Intel (i386/x86_64) and AARCH64.
## How-to
### Modify afl-untracer.c
Read and modify afl-untracer.c then `make`.
To adapt afl-untracer.c to your needs, read the header of the file and then
search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
### Generate patches.txt file
To generate the `patches.txt` file for your target library use the
`ida_get_patchpoints.py` script for IDA Pro or
`ghidra_get_patchpoints.java` for Ghidra.
The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`.
To easily run the scripts without needing to run the GUI with Ghidra:
```
$ /opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
$ rm -rf /tmp/tmp$$
```
### Fuzzing
Example (after modifying afl-untracer.c to your needs, compiling and creating
patches.txt):
```
AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
```
(or even remote via afl-network-proxy).
### Testing and debugging
For testing/debugging you can try:
```
make DEBUG=1
AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer
```
and then you can easily set breakpoints to "breakpoint" and "fuzz".
# Background
This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
This implementation is slower because the traps are not patched out with each
run, but on the other hand gives much better coverage information.

View File

@ -0,0 +1,756 @@
/*
american fuzzy lop++ - afl-untracer skeleton example
---------------------------------------------------
Written by Marc Heuse <mh@mh-sec.de>
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
HOW-TO
======
You only need to change the following:
1. decide if you want to receive data from stdin [DEFAULT] or file(name)
-> use_stdin = 0 if via file, and what the maximum input size is
2. dl load the library you want to fuzz, lookup the functions you need
and setup the calls to these
3. in the while loop you call the functions in the necessary order -
incl the cleanup. the cleanup is important!
Just look these steps up in the code, look for "// STEP x:"
*/
#define __USE_GNU
#define _GNU_SOURCE
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#if defined(__linux__)
#include <sys/ucontext.h>
#elif defined(__APPLE__) && defined(__LP64__)
#include <mach-o/dyld_images.h>
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/user.h>
#else
#error "Unsupported platform"
#endif
#define MEMORY_MAP_DECREMENT 0x200000000000
#define MAX_LIB_COUNT 128
// STEP 1:
/* use stdin (1) or a file on the commandline (0) */
static u32 use_stdin = 1;
/* This is were the testcase data is written into */
static u8 buf[10000]; // this is the maximum size for a test case! set it!
/* If you want to have debug output set this to 1, can also be set with
AFL_DEBUG */
static u32 debug = 0;
// END STEP 1
typedef struct library_list {
u8 *name;
u64 addr_start, addr_end;
} library_list_t;
#ifdef __ANDROID__
u32 __afl_map_size = MAP_SIZE;
u32 do_exit;
#else
__thread u32 __afl_map_size = MAP_SIZE;
__thread u32 do_exit;
#endif
static pid_t pid = 65537;
static pthread_t __afl_thread;
static u8 __afl_dummy[MAP_SIZE];
static u8 * __afl_area_ptr = __afl_dummy;
static u8 * inputfile; // this will point to argv[1]
static u32 len;
static library_list_t liblist[MAX_LIB_COUNT];
static u32 liblist_cnt;
static void sigtrap_handler(int signum, siginfo_t *si, void *context);
static void fuzz();
/* read the library information */
void read_library_information() {
#if defined(__linux__)
FILE *f;
u8 buf[1024], *b, *m, *e, *n;
if ((f = fopen("/proc/self/maps", "r")) == NULL)
FATAL("cannot open /proc/self/maps");
if (debug) fprintf(stderr, "Library list:\n");
while (fgets(buf, sizeof(buf), f)) {
if (strstr(buf, " r-x")) {
if (liblist_cnt >= MAX_LIB_COUNT) {
WARNF("too many libraries to old, maximum count of %d reached",
liblist_cnt);
return;
}
b = buf;
m = index(buf, '-');
e = index(buf, ' ');
if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' ');
if (n &&
((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
n = NULL;
else
n++;
if (b && m && e && n && *n) {
*m++ = 0;
*e = 0;
if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
liblist[liblist_cnt].name = strdup(n);
liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
if (debug)
fprintf(
stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
liblist[liblist_cnt].addr_start,
liblist[liblist_cnt].addr_end - 1);
liblist_cnt++;
}
}
}
if (debug) fprintf(stderr, "\n");
#elif defined(__FreeBSD__)
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
char * buf, *start, *end;
size_t miblen = sizeof(mib) / sizeof(mib[0]);
size_t len;
if (debug) fprintf(stderr, "Library list:\n");
if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
len = len * 4 / 3;
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (buf == MAP_FAILED) { return; }
if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
munmap(buf, len);
return;
}
start = buf;
end = buf + len;
while (start < end) {
struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
size_t size = region->kve_structsize;
if (size == 0) { break; }
if ((region->kve_protection & KVME_PROT_READ) &&
!(region->kve_protection & KVME_PROT_EXEC)) {
liblist[liblist_cnt].name =
region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
liblist[liblist_cnt].addr_start = region->kve_start;
liblist[liblist_cnt].addr_end = region->kve_end;
if (debug) {
fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
liblist[liblist_cnt].addr_start,
liblist[liblist_cnt].addr_end - 1);
}
liblist_cnt++;
}
start += size;
}
#endif
}
library_list_t *find_library(char *name) {
#if defined(__linux__)
u32 i;
for (i = 0; i < liblist_cnt; i++)
if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
#elif defined(__APPLE__) && defined(__LP64__)
kern_return_t err;
static library_list_t lib;
// get the list of all loaded modules from dyld
// the task_info mach API will get the address of the dyld all_image_info
// struct for the given task from which we can get the names and load
// addresses of all modules
task_dyld_info_data_t task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
err = task_info(mach_task_self(), TASK_DYLD_INFO,
(task_info_t)&task_dyld_info, &count);
const struct dyld_all_image_infos *all_image_infos =
(const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
const struct dyld_image_info *image_infos = all_image_infos->infoArray;
for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
const char * image_name = image_infos[i].imageFilePath;
mach_vm_address_t image_load_address =
(mach_vm_address_t)image_infos[i].imageLoadAddress;
if (strstr(image_name, name)) {
lib.name = name;
lib.addr_start = (u64)image_load_address;
lib.addr_end = 0;
return &lib;
}
}
#endif
return NULL;
}
/* for having an easy breakpoint location after loading the shared library */
// this seems to work for clang too. nice :) requires gcc 4.4+
#pragma GCC push_options
#pragma GCC optimize("O0")
void breakpoint() {
if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
}
#pragma GCC pop_options
/* Error reporting to forkserver controller */
void send_forkserver_error(int error) {
u32 status;
if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
}
/* SHM setup. */
static void __afl_map_shm(void) {
char *id_str = getenv(SHM_ENV_VAR);
char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
u32 val = atoi(ptr);
if (val > 0) __afl_map_size = val;
}
if (__afl_map_size > MAP_SIZE) {
if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
fprintf(stderr,
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
fprintf(stderr,
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_map_size);
}
}
if (id_str) {
#ifdef USEMMAP
const char * shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1);
}
/* map the shared memory segment to the address space of the process */
shm_base =
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED) {
close(shm_fd);
shm_fd = -1;
fprintf(stderr, "mmap() failed\n");
send_forkserver_error(FS_ERROR_MMAP);
exit(2);
}
__afl_area_ptr = shm_base;
#else
u32 shm_id = atoi(id_str);
__afl_area_ptr = shmat(shm_id, 0, 0);
#endif
if (__afl_area_ptr == (void *)-1) {
send_forkserver_error(FS_ERROR_SHMAT);
exit(1);
}
/* Write something into the bitmap so that the parent doesn't give up */
__afl_area_ptr[0] = 1;
}
}
/* Fork server logic. */
static void __afl_start_forkserver(void) {
u8 tmp[4] = {0, 0, 0, 0};
u32 status = 0;
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (status) status |= (FS_OPT_ENABLED);
memcpy(tmp, &status, 4);
/* Phone home and tell the parent that we're OK. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
// fprintf(stderr, "write0 %d\n", do_exit);
}
static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
s32 status;
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
// fprintf(stderr, "read %d\n", do_exit);
/* we have a testcase - read it if we read from stdin */
if (use_stdin) {
if ((status = read(0, buf, max_len)) <= 0) exit(-1);
} else
status = 1;
// fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
/* report that we are starting the target */
if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
// fprintf(stderr, "write1 %d\n", do_exit);
return status;
}
static void __afl_end_testcase(int status) {
if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
// fprintf(stderr, "write2 %d\n", do_exit);
if (do_exit) exit(0);
}
#ifdef __aarch64__
#define SHADOW(addr) \
((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
MEMORY_MAP_DECREMENT - \
((uintptr_t)addr & 0x7) * 0x10000000000))
#else
#define SHADOW(addr) \
((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
MEMORY_MAP_DECREMENT - \
((uintptr_t)addr & 0x3) * 0x10000000000))
#endif
void setup_trap_instrumentation() {
library_list_t *lib_base = NULL;
size_t lib_size = 0;
u8 * lib_addr;
char * line = NULL;
size_t nread, len = 0;
char * filename = getenv("AFL_UNTRACER_FILE");
if (!filename) filename = getenv("TRAPFUZZ_FILE");
if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
FILE *patches = fopen(filename, "r");
if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
// Index into the coverage bitmap for the current trap instruction.
#ifdef __aarch64__
uint64_t bitmap_index = 0;
#else
uint32_t bitmap_index = 0;
#endif
while ((nread = getline(&line, &len, patches)) != -1) {
char *end = line + len;
char *col = strchr(line, ':');
if (col) {
// It's a library:size pair
*col++ = 0;
lib_base = find_library(line);
if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
// we ignore the defined lib_size
lib_size = strtoul(col, NULL, 16);
#if (__linux__)
if (lib_size < lib_base->addr_end - lib_base->addr_start)
lib_size = lib_base->addr_end - lib_base->addr_start;
#endif
if (lib_size % 0x1000 != 0)
WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
lib_size);
lib_addr = (u8 *)lib_base->addr_start;
// Make library code writable.
if (mprotect((void *)lib_addr, lib_size,
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
FATAL("Failed to mprotect library %s writable", line);
// Create shadow memory.
#ifdef __aarch64__
for (int i = 0; i < 8; i++) {
#else
for (int i = 0; i < 4; i++) {
#endif
void *shadow_addr = SHADOW(lib_addr + i);
void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
if (debug)
fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
shadow + lib_size - 1, lib_addr);
if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
}
// Done, continue with next line.
continue;
}
// It's an offset, parse it and do the patching.
unsigned long offset = strtoul(line, NULL, 16);
if (offset > lib_size)
FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
offset, lib_size);
if (bitmap_index >= __afl_map_size)
FATAL("Too many basic blocks to instrument");
#ifdef __arch64__
uint64_t
#else
uint32_t
#endif
*shadow = SHADOW(lib_addr + offset);
if (*shadow != 0) continue; // skip duplicates
// Make lookup entry in shadow memory.
#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
defined(__i386__))
// this is for Intel x64
uint8_t orig_byte = lib_addr[offset];
*shadow = (bitmap_index << 8) | orig_byte;
lib_addr[offset] = 0xcc; // replace instruction with debug trap
if (debug)
fprintf(stderr,
"Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
lib_addr, offset, lib_addr + offset, orig_byte, shadow,
bitmap_index, *shadow);
#elif defined(__aarch64__)
// this is for aarch64
uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
uint32_t orig_bytes = *patch_bytes;
*shadow = (bitmap_index << 32) | orig_bytes;
*patch_bytes = 0xd4200000; // replace instruction with debug trap
if (debug)
fprintf(stderr,
"Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
bitmap_index, *shadow);
#else
// this will be ARM and AARCH64
// for ARM we will need to identify if the code is in thumb or ARM
#error "non x86_64/aarch64 not supported yet"
//__arm__:
// linux thumb: 0xde01
// linux arm: 0xe7f001f0
//__aarch64__:
// linux aarch64: 0xd4200000
#endif
bitmap_index++;
}
free(line);
fclose(patches);
// Install signal handler for SIGTRAP.
struct sigaction s;
s.sa_flags = SA_SIGINFO;
s.sa_sigaction = sigtrap_handler;
sigemptyset(&s.sa_mask);
sigaction(SIGTRAP, &s, 0);
if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
__afl_map_size = bitmap_index;
if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
}
/* the signal handler for the traps / debugging interrupts
No debug output here because this would cost speed */
static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
uint64_t addr;
// Must re-execute the instruction, so decrement PC by one instruction.
ucontext_t *ctx = (ucontext_t *)context;
#if defined(__APPLE__) && defined(__LP64__)
ctx->uc_mcontext->__ss.__rip -= 1;
addr = ctx->uc_mcontext->__ss.__rip;
#elif defined(__linux__)
#if defined(__x86_64__) || defined(__i386__)
ctx->uc_mcontext.gregs[REG_RIP] -= 1;
addr = ctx->uc_mcontext.gregs[REG_RIP];
#elif defined(__aarch64__)
ctx->uc_mcontext.pc -= 4;
addr = ctx->uc_mcontext.pc;
#else
#error "Unsupported processor"
#endif
#elif defined(__FreeBSD__) && defined(__LP64__)
ctx->uc_mcontext.mc_rip -= 1;
addr = ctx->uc_mcontext.mc_rip;
#else
#error "Unsupported platform"
#endif
// fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
// si->si_addr);
// If the trap didn't come from our instrumentation, then we probably will
// just segfault here
uint8_t *faultaddr;
if (unlikely(si->si_addr))
faultaddr = (u8 *)si->si_addr - 1;
else
faultaddr = (u8 *)addr;
// if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
uint32_t shadow = *SHADOW(faultaddr);
uint8_t orig_byte = shadow & 0xff;
uint32_t index = shadow >> 8;
// if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
// shadow, orig_byte, index);
// Index zero is invalid so that it is still possible to catch actual trap
// instructions in instrumented libraries.
if (unlikely(index == 0)) abort();
// Restore original instruction
*faultaddr = orig_byte;
__afl_area_ptr[index] = 128;
}
/* here you need to specify the parameter for the target function */
static void *(*o_function)(u8 *buf, int len);
/* the MAIN function */
int main(int argc, char *argv[]) {
pid = getpid();
if (getenv("AFL_DEBUG")) debug = 1;
/* by default we use stdin, but also a filename can be passed, in this
case the input is argv[1] and we have to disable stdin */
if (argc > 1) {
use_stdin = 0;
inputfile = argv[1];
}
// STEP 2: load the library you want to fuzz and lookup the functions,
// inclusive of the cleanup functions
// NOTE: above the main() you have to define the functions!
void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
if (!dl) FATAL("could not find target library");
o_function = dlsym(dl, "testinstr");
if (!o_function) FATAL("could not resolve target function from library");
if (debug) fprintf(stderr, "Function address: %p\n", o_function);
// END STEP 2
/* setup instrumentation, shared memory and forkserver */
breakpoint();
read_library_information();
setup_trap_instrumentation();
__afl_map_shm();
__afl_start_forkserver();
while (1) {
if ((pid = fork()) == -1) PFATAL("fork failed");
if (pid) {
u32 status;
if (waitpid(pid, &status, 0) < 0) exit(1);
/* report the test case is done and wait for the next */
__afl_end_testcase(status);
} else {
pid = getpid();
while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
// in this function the fuzz magic happens, this is STEP 3
fuzz();
// we can use _exit which is faster because our target library
// was loaded via dlopen and therefore cannot have deconstructors
// registered.
_exit(0);
}
}
}
return 0;
}
static void fuzz() {
// STEP 3: call the function to fuzz, also the functions you might
// need to call to prepare the function and - important! -
// to clean everything up
// in this example we use the input file, not stdin!
(*o_function)(buf, len);
// normally you also need to cleanup
//(*o_LibFree)(foo);
// END STEP 3
}

View File

@ -0,0 +1,84 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer)
//
// Copy to ..../Ghidra/Features/Search/ghidra_scripts/
// Writes the results to ~/Desktop/patches.txt
//
// This is my very first Ghidra script. I am sure this could be done better.
//
//@category Search
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.mem.*;
import java.io.*;
public class ghidra_get_patchpoints extends GhidraScript {
@Override
public void run() throws Exception {
long segment_start = 0;
Memory memory = currentProgram.getMemory();
MultEntSubModel model = new MultEntSubModel(currentProgram);
CodeBlockIterator subIter = model.getCodeBlocks(monitor);
BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt"));
while (subIter.hasNext()) {
CodeBlock multiEntryBlock = subIter.next();
SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram);
CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor);
while (bbIter.hasNext()) {
CodeBlock basicBlock = bbIter.next();
if (segment_start == 0) {
Address firstAddr = basicBlock.getFirstStartAddress();
long firstBlockAddr = firstAddr.getAddressableWordOffset();
MemoryBlock mb = memory.getBlock(firstAddr);
Address startAddr = mb.getStart();
Address endAddr = mb.getEnd();
segment_start = startAddr.getAddressableWordOffset();
if ((firstBlockAddr - segment_start) >= 0x1000)
segment_start += 0x1000;
long segment_end = endAddr.getAddressableWordOffset();
long segment_size = segment_end - segment_start;
if ((segment_size % 0x1000) > 0)
segment_size = (((segment_size / 0x1000) + 1) * 0x1000);
out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n");
//println("Start: " + Long.toHexString(segment_start));
//println("End: " + Long.toHexString(segment_end));
}
if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0)
out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n");
}
}
out.close();
}
}

View File

@ -0,0 +1,62 @@
#
# IDAPython script for IDA Pro
# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py
#
import idautils
import idaapi
import ida_nalt
import idc
# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
from os.path import expanduser
home = expanduser("~")
patchpoints = set()
max_offset = 0
for seg_ea in idautils.Segments():
name = idc.get_segm_name(seg_ea)
#print("Segment: " + name)
if name != "__text" and name != ".text":
continue
start = idc.get_segm_start(seg_ea)
end = idc.get_segm_end(seg_ea)
first = 0
subtract_addr = 0
#print("Start: " + hex(start) + " End: " + hex(end))
for func_ea in idautils.Functions(start, end):
f = idaapi.get_func(func_ea)
if not f:
continue
for block in idaapi.FlowChart(f):
if start <= block.start_ea < end:
if first == 0:
if block.start_ea >= 0x1000:
subtract_addr = 0x1000
first = 1
max_offset = max(max_offset, block.start_ea)
patchpoints.add(block.start_ea - subtract_addr)
#else:
# print("Warning: broken CFG?")
# Round up max_offset to page size
size = max_offset
rem = size % 0x1000
if rem != 0:
size += 0x1000 - rem
print("Writing to " + home + "/Desktop/patches.txt")
with open(home + "/Desktop/patches.txt", "w") as f:
f.write(ida_nalt.get_root_filename() + ':' + hex(size) + '\n')
f.write('\n'.join(map(hex, sorted(patchpoints))))
f.write('\n')
print("Done, found {} patchpoints".format(len(patchpoints)))
# For headless script running remove the comment from the next line
#ida_pro.qexit()

View File

@ -0,0 +1,35 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void testinstr(char *buf, int len) {
if (len < 1) return;
buf[len] = 0;
// we support three input cases
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else if (buf[0] == '1')
printf("Pretty sure that is a one!\n");
else
printf("Neither one or zero? How quaint!\n");
}

View File

@ -0,0 +1,23 @@
libtestinstr.so:0x2000L
0x1050L
0x1063L
0x106fL
0x1078L
0x1080L
0x10a4L
0x10b0L
0x10b8L
0x10c0L
0x10c9L
0x10d7L
0x10e3L
0x10f8L
0x1100L
0x1105L
0x111aL
0x1135L
0x1143L
0x114eL
0x115cL
0x116aL
0x116bL

View File

@ -31,8 +31,10 @@ LDFLAGS += $(LDFLAGS_ADD)
M32FLAG = -m32
M64FLAG = -m64
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 $$?)
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
__M32FLAG=$(_M32FLAG:00=-mbe32)
@ -42,10 +44,10 @@ M32FLAG=$(___M32FLAG)
all: argvfuzz32.so argvfuzz64.so
argvfuzz32.so: argvfuzz.c
-$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "argvfuzz32 build failure (that's fine)"
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)"
argvfuzz64.so: argvfuzz.c
-$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "argvfuzz64 build failure (that's fine)"
-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)"
install: argvfuzz32.so argvfuzz64.so
install -d -m 755 $(DESTDIR)$(HELPER_PATH)/

View File

@ -91,10 +91,10 @@ for crash in $DIR/crashes/id:*; do
for a in $@; do
if [ "$a" = "@@" ] ; then
args="$use_args $crash"
use_args="$use_args $crash"
unset use_stdio
else
args="$use_args $a"
use_args="$use_args $a"
fi
done

View File

@ -6,6 +6,9 @@ See [docs/custom_mutators.md](../docs/custom_mutators.md) for more information
Note that if you compile with python3.7 you must use python3 scripts, and if
you use python2.7 to compile python2 scripts!
simple_example.c - most simplest example. generates a random sized buffer
filled with 'A'
example.c - this is a simple example written in C and should be compiled to a
shared library. Use make to compile it and produce libexamplemutator.so

View File

@ -38,7 +38,7 @@ typedef struct my_mutator {
BUF_VAR(u8, data);
BUF_VAR(u8, havoc);
BUF_VAR(u8, trim);
BUF_VAR(u8, pre_save);
BUF_VAR(u8, post_process);
} my_mutator_t;
@ -139,11 +139,12 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t 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) {
size_t afl_custom_post_process(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) {
uint8_t *post_process_buf =
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
if (!post_process_buf) {
perror("custom mutator realloc failed.");
*out_buf = NULL;
@ -151,14 +152,14 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size,
}
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] = '+';
memcpy(post_process_buf + 5, buf, buf_size);
post_process_buf[0] = 'A';
post_process_buf[1] = 'F';
post_process_buf[2] = 'L';
post_process_buf[3] = '+';
post_process_buf[4] = '+';
*out_buf = pre_save_buf;
*out_buf = post_process_buf;
return buf_size + 5;
@ -364,7 +365,7 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->pre_save_buf);
free(data->post_process_buf);
free(data->havoc_buf);
free(data->data_buf);
free(data->fuzz_buf);

View File

@ -21,6 +21,7 @@ COMMANDS = [
b"GET",
b"PUT",
b"DEL",
b"AAAAAAAAAAAAAAAAA",
]
@ -119,7 +120,7 @@ def fuzz(buf, add_buf, max_size):
#
# return next_index
#
# def pre_save(buf):
# def post_process(buf):
# '''
# Called just before the execution to write the test case in the format
# expected by the target

View File

@ -0,0 +1,74 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
#include "custom_mutator_helpers.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef _FIXED_CHAR
#define 0x41
#endif
typedef struct my_mutator {
afl_t *afl;
// Reused buffers:
BUF_VAR(u8, fuzz);
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
data->afl = afl;
return data;
}
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf,
size_t add_buf_size, // add_buf can be NULL
size_t max_size) {
int size = (rand() % 100) + 1;
if (size > max_size) size = max_size;
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
if (!mutated_out) {
*out_buf = NULL;
perror("custom mutator allocation (maybe_grow)");
return 0; /* afl-fuzz will very likely error out after this. */
}
memset(mutated_out, _FIXED_CHAR, size);
*out_buf = mutated_out;
return size;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->fuzz_buf);
free(data);
}

View File

@ -1,159 +0,0 @@
/*
american fuzzy lop++ - postprocessor library example
--------------------------------------------------
Originally written by Michal Zalewski
Edited by Dominik Maier, 2020
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Postprocessor libraries can be passed to afl-fuzz to perform final cleanup
of any mutated test cases - for example, to fix up checksums in PNG files.
Please heed the following warnings:
1) In almost all cases, it is more productive to comment out checksum logic
in the targeted binary (as shown in ../libpng_no_checksum/). One possible
exception is the process of fuzzing binary-only software in QEMU mode.
2) The use of postprocessors for anything other than checksums is
questionable and may cause more harm than good. AFL is normally pretty good
about dealing with length fields, magic values, etc.
3) Postprocessors that do anything non-trivial must be extremely robust to
gracefully handle malformed data and other error conditions - otherwise,
they will crash and take afl-fuzz down with them. Be wary of reading past
*len and of integer overflows when calculating file offsets.
In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really,
honestly know what you're doing =)
With that out of the way: the postprocessor library is passed to afl-fuzz
via AFL_POST_LIBRARY. The library must be compiled with:
gcc -shared -Wall -O3 post_library.so.c -o post_library.so
AFL will call the afl_postprocess() function for every mutated output buffer.
From there, you have three choices:
1) If you don't want to modify the test case, simply 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 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 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).
*** 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".
PS. If you don't like C, you can try out the unix-based wrapper from
Ben Nagy instead: https://github.com/bnagy/aflfix
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Header that must be present at the beginning of every test case: */
#define HEADER "GIF89a"
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: */
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. */
if (len < strlen(HEADER)) return 0;
/* Do nothing for buffers that already start with the expected header. */
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
*out_buf = in_buf;
return len;
}
/* Allocate memory for new buffer, reusing previous allocation if
possible. */
*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 (!*out_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

@ -1,156 +0,0 @@
/*
american fuzzy lop++ - postprocessor for PNG
------------------------------------------
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.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
See post_library.so.c for a general discussion of how to implement
postprocessors. This specific postprocessor attempts to fix up PNG
checksums, providing a slightly more complicated example than found
in post_library.so.c.
Compile with:
gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <zlib.h>
#include <arpa/inet.h>
/* A macro to round an integer up to 4 kB. */
#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
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;
}
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;
/* Don't do anything if there's not enough room for the PNG header
(8 bytes). */
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) {
unsigned int chunk_len, real_cksum, file_cksum;
/* Chunk length is the first big-endian dword in the chunk. */
chunk_len = ntohl(*(uint32_t *)(in_buf + pos));
/* Bail out if chunk size is too big or goes past EOF. */
if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
/* Chunk checksum is calculated for chunk ID (dword) and the actual
payload. */
real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4));
/* The in-file checksum is the last dword past the chunk data. */
file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len);
/* If the checksums do not match, we need to fix the file. */
if (real_cksum != file_cksum) {
/* First modification? Make a copy of the input buffer. Round size
up to 4 kB to minimize the number of reallocs needed. */
if (new_buf == in_buf) {
if (len <= data->size) {
new_buf = data->buf;
} else {
new_buf = realloc(data->buf, UP4K(len));
if (!new_buf) {
*out_buf = in_buf;
return len;
}
data->buf = new_buf;
data->size = UP4K(len);
memcpy(new_buf, in_buf, len);
}
}
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
}
/* Skip the entire chunk and move to the next one. */
pos += 12 + chunk_len;
}
*out_buf = new_buf;
return len;
}
/* Gets called afterwards */
void afl_postprocess_deinit(post_state_t *data) {
free(data->buf);
free(data);
}

View File

@ -16,7 +16,8 @@ int target_func(unsigned char *buf, int size) {
}
break;
default: break;
default:
break;
}

View File

@ -29,8 +29,10 @@ LDFLAGS += $(LDFLAGS_ADD)
M32FLAG = -m32
M64FLAG = -m64
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 $$?)
CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
__M32FLAG=$(_M32FLAG:00=-mbe32)
@ -45,10 +47,10 @@ M32FLAG=$(___M32FLAG)
all: socketfuzz32.so socketfuzz64.so
socketfuzz32.so: socketfuzz.c
-$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "socketfuzz32 build failure (that's fine)"
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)"
socketfuzz64.so: socketfuzz.c
-$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "socketfuzz64 build failure (that's fine)"
-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)"
install: socketfuzz32.so socketfuzz64.so
install -d -m 755 $(DESTDIR)$(HELPER_PATH)/

View File

@ -68,8 +68,7 @@ LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt)
CFLAGS += $(CFLAGS_ADD)
LDFLAGS += $(LDFLAGS_ADD)
PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
PROGS = ../afl-gcc-pass.so ../afl-gcc-fast ../afl-gcc-rt.o
all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done

View File

@ -121,12 +121,18 @@ static void edit_params(u32 argc, char **argv) {
if (!strcmp(name, "afl-g++-fast")) {
u8 *alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
} else if (!strcmp(name, "afl-gcc-fast")) {
u8 *alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
} else {
u8 *alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
FATAL(
"Name of the binary is not a known name, expected afl-(gcc|g++)-fast");
}
@ -364,6 +370,16 @@ int main(int argc, char **argv, char **envp) {
be_quiet = 1;
u8 *ptr;
if (!be_quiet &&
((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
u32 map_size = atoi(ptr);
if (map_size != MAP_SIZE)
FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast");
}
check_environment_vars(envp);
find_obj(argv[0]);

View File

@ -55,10 +55,10 @@
/* clear helper macros AFL types pull in, which intervene with gcc-plugin
* headers from GCC-8 */
#ifdef likely
#undef likely
#undef likely
#endif
#ifdef unlikely
#undef unlikely
#undef unlikely
#endif
#include <stdio.h>
@ -295,16 +295,16 @@ static unsigned int inline_instrument(function *fun) {
update_stmt(g);
#if 1
#if 0
#if 0
tree addr = build2(ADDR_EXPR, map_type, map_ptr, area_off);
g = gimple_build_assign(map_ptr2, MODIFY_EXPR, addr);
gimple_seq_add_stmt(&seq, g); // map_ptr2 = map_ptr + area_off
update_stmt(g);
#else
#else
g = gimple_build_assign(map_ptr2, PLUS_EXPR, map_ptr, area_off);
gimple_seq_add_stmt(&seq, g); // map_ptr2 = map_ptr + area_off
update_stmt(g);
#endif
#endif
// gimple_assign <mem_ref, _3, *p_6, NULL, NULL>
tree tmp1 = create_tmp_var_raw(unsigned_char_type_node, "tmp1");

View File

@ -20,13 +20,13 @@
*/
#ifdef __ANDROID__
#include "android-ashmem.h"
#include "android-ashmem.h"
#endif
#include "../config.h"
#include "../types.h"
#ifdef USEMMAP
#include <stdio.h>
#include <stdio.h>
#endif
#include <stdlib.h>
#include <signal.h>
@ -138,8 +138,9 @@ static void __afl_map_shm(void) {
static void __afl_start_forkserver(void) {
static u8 tmp[4];
s32 child_pid;
u8 tmp[4] = {0, 0, 0, 0};
u32 map_size = MAP_SIZE;
s32 child_pid;
u8 child_stopped = 0;
@ -148,6 +149,13 @@ static void __afl_start_forkserver(void) {
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
if (MAP_SIZE <= 0x800000) {
map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
memcpy(tmp, &map_size, 4);
}
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
while (1) {

View File

@ -404,9 +404,9 @@ static const u8 *main_payload_32 =
recognize .string. */
#ifdef __APPLE__
#define CALL_L64(str) "call _" str "\n"
#define CALL_L64(str) "call _" str "\n"
#else
#define CALL_L64(str) "call " str "@PLT\n"
#define CALL_L64(str) "call " str "@PLT\n"
#endif /* ^__APPLE__ */
static const u8 *main_payload_64 =
@ -744,9 +744,9 @@ static const u8 *main_payload_64 =
#ifdef __APPLE__
" .comm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY
#ifndef COVERAGE_ONLY
" .comm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */
#endif /* !COVERAGE_ONLY */
" .comm __afl_fork_pid, 4\n"
" .comm __afl_temp, 4\n"
" .comm __afl_setup_failure, 1\n"
@ -754,9 +754,9 @@ static const u8 *main_payload_64 =
#else
" .lcomm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY
#ifndef COVERAGE_ONLY
" .lcomm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */
#endif /* !COVERAGE_ONLY */
" .lcomm __afl_fork_pid, 4\n"
" .lcomm __afl_temp, 4\n"
" .lcomm __afl_setup_failure, 1\n"

View File

@ -31,12 +31,14 @@
#define MESSAGES_TO_STDOUT
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#define _GNU_SOURCE 1
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#define _FILE_OFFSET_BITS 64
#ifdef __ANDROID__
#include "android-ashmem.h"
#include "android-ashmem.h"
#endif
#include "config.h"
@ -74,7 +76,7 @@
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(__NetBSD__) || defined(__DragonFly__)
#include <sys/sysctl.h>
#include <sys/sysctl.h>
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
/* For systems that have sched_setaffinity; right now just Linux, but one
@ -82,31 +84,31 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__DragonFly__)
#define HAVE_AFFINITY 1
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <sys/param.h>
#if defined(__FreeBSD__)
#include <sys/cpuset.h>
#endif
#include <sys/user.h>
#include <pthread.h>
#include <pthread_np.h>
#define cpu_set_t cpuset_t
#elif defined(__NetBSD__)
#include <pthread.h>
#endif
#define HAVE_AFFINITY 1
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <sys/param.h>
#if defined(__FreeBSD__)
#include <sys/cpuset.h>
#endif
#include <sys/user.h>
#include <pthread.h>
#include <pthread_np.h>
#define cpu_set_t cpuset_t
#elif defined(__NetBSD__)
#include <pthread.h>
#endif
#endif /* __linux__ */
#ifdef __APPLE__
#include <TargetConditionals.h>
#include <TargetConditionals.h>
#endif
#undef LIST_FOREACH /* clashes with FreeBSD */
#include "list.h"
#ifndef SIMPLE_FILES
#define CASE_PREFIX "id:"
#define CASE_PREFIX "id:"
#else
#define CASE_PREFIX "id_"
#define CASE_PREFIX "id_"
#endif /* ^!SIMPLE_FILES */
#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */
@ -195,19 +197,6 @@ enum {
};
/* Execution status fault codes */
enum {
/* 00 */ FAULT_NONE,
/* 01 */ FAULT_TMOUT,
/* 02 */ FAULT_CRASH,
/* 03 */ FAULT_ERROR,
/* 04 */ FAULT_NOINST,
/* 05 */ FAULT_NOBITS
};
#define operator_num 16
#define swarm_num 5
#define period_core 500000
@ -242,36 +231,36 @@ enum {
/* Python stuff */
#ifdef USE_PYTHON
// because Python sets stuff it should not ...
#ifdef _POSIX_C_SOURCE
#define _SAVE_POSIX_C_SOURCE _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#ifdef _XOPEN_SOURCE
#define _SAVE_XOPEN_SOURCE _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
// because Python sets stuff it should not ...
#ifdef _POSIX_C_SOURCE
#define _SAVE_POSIX_C_SOURCE _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#ifdef _XOPEN_SOURCE
#define _SAVE_XOPEN_SOURCE _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#include <Python.h>
#include <Python.h>
#ifdef _SAVE_POSIX_C_SOURCE
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE _SAVE_POSIX_C_SOURCE
#endif
#ifdef _SAVE_XOPEN_SOURCE
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#define _XOPEN_SOURCE _SAVE_XOPEN_SOURCE
#endif
#ifdef _SAVE_POSIX_C_SOURCE
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE _SAVE_POSIX_C_SOURCE
#endif
#ifdef _SAVE_XOPEN_SOURCE
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#define _XOPEN_SOURCE _SAVE_XOPEN_SOURCE
#endif
enum {
/* 00 */ PY_FUNC_INIT,
/* 01 */ PY_FUNC_FUZZ,
/* 02 */ PY_FUNC_PRE_SAVE,
/* 02 */ PY_FUNC_POST_PROCESS,
/* 03 */ PY_FUNC_INIT_TRIM,
/* 04 */ PY_FUNC_POST_TRIM,
/* 05 */ PY_FUNC_TRIM,
@ -294,8 +283,8 @@ typedef struct py_mutator {
u8 * fuzz_buf;
size_t fuzz_size;
u8 * pre_save_buf;
size_t pre_save_size;
u8 * post_process_buf;
size_t post_process_size;
u8 * trim_buf;
size_t trim_size;
@ -331,14 +320,21 @@ typedef struct afl_env_vars {
u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check,
afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
afl_bench_until_crash, afl_debug_child_output, afl_autoresume;
afl_bench_until_crash, afl_debug_child_output, afl_autoresume,
afl_cal_fast;
u8 *afl_tmpdir, *afl_post_library, *afl_custom_mutator_library,
*afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes,
*afl_preload;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_skip_crashes, *afl_preload;
} afl_env_vars_t;
struct afl_pass_stat {
u8 total;
u8 faileds;
};
typedef struct afl_state {
/* Position of this state in the global states list */
@ -353,14 +349,14 @@ typedef struct afl_state {
/* MOpt:
Lots of globals, but mostly for the status UI and other things where it
really makes no sense to haul them around as function parameters. */
u64 limit_time_puppet, orig_hit_cnt_puppet, last_limit_time_start,
tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find,
most_time_key, most_time, most_execs_key, most_execs, old_hit_count,
force_ui_update;
u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key,
most_time, most_execs_key, most_execs, old_hit_count, force_ui_update;
MOpt_globals_t mopt_globals_core, mopt_globals_pilot;
s32 SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, key_module;
s32 limit_time_puppet, SPLICE_CYCLES_puppet, limit_time_sig, key_puppet,
key_module;
double w_init, w_end, w_now;
@ -410,7 +406,9 @@ typedef struct afl_state {
no_unlink, /* do not unlink cur_input */
debug, /* Debug mode */
custom_only, /* Custom mutator only mode */
python_only; /* Python-only mode */
python_only, /* Python-only mode */
is_master, /* if this is a master */
is_slave; /* if this is a slave */
u32 stats_update_freq; /* Stats update frequency (execs) */
@ -421,11 +419,9 @@ typedef struct afl_state {
size_t (*radamsa_mutate_ptr)(u8 *, size_t, u8 *, size_t, u32);
u8 skip_deterministic, /* Skip deterministic stages? */
force_deterministic, /* Force deterministic stages? */
use_splicing, /* Recombine input files? */
dumb_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */
kill_signal, /* Signal that killed the child */
resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */
@ -439,7 +435,6 @@ typedef struct afl_state {
no_arith, /* Skip most arithmetic ops */
shuffle_queue, /* Shuffle input queue? */
bitmap_changed, /* Time to update bitmap? */
qemu_mode, /* Running in QEMU mode? */
unicorn_mode, /* Running in Unicorn mode? */
use_wine, /* Use WINE with QEMU mode */
skip_requested, /* Skip request, via SIGUSR1 */
@ -450,11 +445,11 @@ typedef struct afl_state {
fast_cal, /* Try to calibrate faster? */
disable_trim; /* Never trim in fuzz_one */
u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */
virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */
u8 *virgin_bits, /* Regions yet untouched by fuzzing */
*virgin_tmout, /* Bits we haven't seen in tmouts */
*virgin_crash; /* Bits we haven't seen in crashes */
u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */
u8 *var_bytes; /* Bytes that appear to be variable */
volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen; /* Window resized? */
@ -481,7 +476,6 @@ typedef struct afl_state {
total_tmouts, /* Total number of timeouts */
unique_tmouts, /* Timeouts with unique signatures */
unique_hangs, /* Hangs with unique signatures */
total_execs, /* Total execve() calls */
last_crash_execs, /* Exec counter at last crash */
queue_cycle, /* Queue round counter */
cycles_wo_finds, /* Cycles without any new paths */
@ -543,7 +537,7 @@ typedef struct afl_state {
*queue_top, /* Top of the list */
*q_prev100; /* Previous 100 marker */
struct queue_entry *top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */
struct queue_entry **top_rated; /* Top entries for bitmap bytes */
struct extra_data *extras; /* Extra tokens to fuzz with */
u32 extras_cnt; /* Total number of tokens read */
@ -551,16 +545,14 @@ typedef struct afl_state {
struct extra_data *a_extras; /* Automatically selected extras */
u32 a_extras_cnt; /* Total number of tokens available */
/* afl_postprocess API */
void *(*post_init)(struct afl_state *afl);
size_t (*post_handler)(void *data, u8 *buf, u32 len, u8 **out_buf);
void *(*post_deinit)(void *data);
void *post_data;
/* afl_postprocess API - Now supported via custom mutators */
struct custom_mutator *post_library_mutator;
/* CmpLog */
char *cmplog_binary;
s32 cmplog_child_pid, cmplog_fsrv_pid;
char * cmplog_binary;
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
/* Custom mutators */
struct custom_mutator *mutator;
@ -569,6 +561,9 @@ typedef struct afl_state {
s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
u32 cmplog_prev_timed_out;
struct afl_pass_stat *pass_stats;
struct cmp_map * orig_cmp_map;
u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
up to 256 */
@ -577,7 +572,9 @@ typedef struct afl_state {
u32 document_counter;
#endif
/* statis file */
void *maybe_add_auto;
/* statistics file */
double last_bitmap_cvg, last_stability, last_eps;
/* plot file saves from last run */
@ -587,9 +584,9 @@ typedef struct afl_state {
u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
double stats_avg_exec;
u8 clean_trace[MAP_SIZE];
u8 clean_trace_custom[MAP_SIZE];
u8 first_trace[MAP_SIZE];
u8 *clean_trace;
u8 *clean_trace_custom;
u8 *first_trace;
/*needed for afl_fuzz_one */
// TODO: see which we can reuse
@ -610,20 +607,23 @@ typedef struct afl_state {
u8 * ex_buf;
size_t ex_size;
u32 custom_mutators_count;
list_t custom_mutator_list;
/* this is a fixed buffer of size map_size that can be used by any function if
* they do not call another function */
u8 *map_tmp_buf;
} afl_state_t;
/* A global pointer to all instances is needed (for now) for signals to arrive
*/
extern list_t afl_states;
struct custom_mutator {
const char *name;
void * dh;
u8 * pre_save_buf;
size_t pre_save_size;
u8 * post_process_buf;
size_t post_process_size;
u8 stacked_custom_prob, stacked_custom;
void *data; /* custom mutator data ptr */
@ -673,8 +673,8 @@ struct custom_mutator {
* It can chose to alter buf in-place, if the space is large enough.
* @return Size of the output buffer.
*/
size_t (*afl_custom_pre_save)(void *data, u8 *buf, size_t buf_size,
u8 **out_buf);
size_t (*afl_custom_post_process)(void *data, u8 *buf, size_t buf_size,
u8 **out_buf);
/**
* This method is called at the start of each trimming operation and receives
@ -797,23 +797,33 @@ struct custom_mutator {
};
void afl_state_init(afl_state_t *);
void afl_state_init(afl_state_t *, uint32_t map_size);
void afl_state_deinit(afl_state_t *);
/* Set stop_soon flag on all childs, kill all childs */
void afl_states_stop(void);
/* Set clear_screen flag on all states */
void afl_states_clear_screen(void);
/* Sets the skip flag on all states */
void afl_states_request_skip(void);
void read_afl_environment(afl_state_t *, char **);
/**** Prototypes ****/
/* Custom mutators */
void setup_custom_mutator(afl_state_t *);
void destroy_custom_mutator(afl_state_t *);
u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf);
void setup_custom_mutators(afl_state_t *);
void destroy_custom_mutators(afl_state_t *);
u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf,
struct custom_mutator *mutator);
/* Python */
#ifdef USE_PYTHON
void finalize_py_module(void *);
struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
void finalize_py_module(void *);
size_t pre_save_py(void *, u8 *, size_t, u8 **);
size_t post_process_py(void *, u8 *, size_t, u8 **);
s32 init_trim_py(void *, u8 *, size_t);
s32 post_trim_py(void *, u8);
size_t trim_py(void *, u8 **);
@ -838,20 +848,19 @@ u32 calculate_score(afl_state_t *, struct queue_entry *);
/* Bitmap */
void read_bitmap(afl_state_t *, u8 *);
void write_bitmap(afl_state_t *);
u32 count_bits(u8 *);
u32 count_bytes(u8 *);
u32 count_non_255_bytes(u8 *);
u32 count_bits(afl_state_t *, u8 *);
u32 count_bytes(afl_state_t *, u8 *);
u32 count_non_255_bytes(afl_state_t *, u8 *);
#ifdef WORD_SIZE_64
void simplify_trace(u64 *);
void classify_counts(u64 *);
void simplify_trace(afl_state_t *, u64 *);
void classify_counts(afl_forkserver_t *);
#else
void simplify_trace(u32 *);
void classify_counts(u32 *);
void simplify_trace(afl_state_t *, u32 *);
void classify_counts(afl_forkserver_t *);
#endif
void init_count_class16(void);
void minimize_bits(u8 *, u8 *);
void minimize_bits(afl_state_t *, u8 *, u8 *);
#ifndef SIMPLE_FILES
u8 *describe_op(afl_state_t *, u8);
#endif
@ -862,7 +871,7 @@ u8 has_new_bits(afl_state_t *, u8 *);
void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
void load_extras(afl_state_t *, u8 *);
void maybe_add_auto(afl_state_t *, u8 *, u32);
void maybe_add_auto(void *, u8 *, u32);
void save_auto(afl_state_t *);
void load_auto(afl_state_t *);
void destroy_extras(afl_state_t *);
@ -876,8 +885,8 @@ void show_init_stats(afl_state_t *);
/* Run */
u8 run_target(afl_state_t *, u32);
void write_to_testcase(afl_state_t *, void *, u32);
fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32);
void write_to_testcase(afl_state_t *, void *, u32);
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
void sync_fuzzers(afl_state_t *);
u8 trim_case(afl_state_t *, struct queue_entry *, u8 *);
@ -920,8 +929,7 @@ void save_cmdline(afl_state_t *, u32, char **);
/* CmpLog */
void init_cmplog_forkserver(afl_state_t *afl);
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
/* RedQueen */
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
@ -957,7 +965,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
static inline u32 get_rand_seed(afl_state_t *afl) {
if (unlikely(afl->fixed_seed)) return (u32)afl->init_seed;
if (unlikely(afl->fixed_seed)) { return (u32)afl->init_seed; }
return afl->rand_seed[0];
}
@ -968,8 +976,12 @@ static inline u32 get_rand_seed(afl_state_t *afl) {
static inline u64 next_p2(u64 val) {
u64 ret = 1;
while (val > ret)
while (val > ret) {
ret <<= 1;
}
return ret;
}

View File

@ -41,53 +41,53 @@
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
#ifndef _WANT_ORIGINAL_AFL_ALLOC
// afl++ stuff without memory corruption checks - for speed
// afl++ stuff without memory corruption checks - for speed
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
#define alloc_printf(_str...) \
({ \
\
u8 *_tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \
snprintf((char *)_tmp, _len + 1, _str); \
_tmp; \
\
})
#define alloc_printf(_str...) \
({ \
\
u8 *_tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \
snprintf((char *)_tmp, _len + 1, _str); \
_tmp; \
\
})
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
#define ALLOC_CHECK_SIZE(_s) \
do { \
\
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0)
#define ALLOC_CHECK_SIZE(_s) \
do { \
\
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0)
/* Macro to check malloc() failures and the like. */
/* Macro to check malloc() failures and the like. */
#define ALLOC_CHECK_RESULT(_r, _s) \
do { \
\
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0)
#define ALLOC_CHECK_RESULT(_r, _s) \
do { \
\
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0)
/* Allocator increments for ck_realloc_block(). */
/* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256
#define ALLOC_BLK_INC 256
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */
static inline void *DFL_ck_alloc_nozero(u32 size) {
u8 *ret;
void *ret;
if (!size) return NULL;
if (!size) { return NULL; }
ALLOC_CHECK_SIZE(size);
ret = malloc(size);
@ -103,7 +103,7 @@ static inline void *DFL_ck_alloc(u32 size) {
void *mem;
if (!size) return NULL;
if (!size) { return NULL; }
mem = DFL_ck_alloc_nozero(size);
return memset(mem, 0, size);
@ -115,7 +115,7 @@ static inline void *DFL_ck_alloc(u32 size) {
static inline void DFL_ck_free(void *mem) {
if (!mem) return;
if (!mem) { return; }
free(mem);
@ -127,7 +127,7 @@ static inline void DFL_ck_free(void *mem) {
static inline void *DFL_ck_realloc(void *orig, u32 size) {
u8 *ret;
void *ret;
if (!size) {
@ -165,7 +165,7 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
u8 *ret;
u32 size;
if (!str) return NULL;
if (!str) { return NULL; }
size = strlen((char *)str) + 1;
@ -182,9 +182,9 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
static inline void *DFL_ck_memdup(void *mem, u32 size) {
u8 *ret;
void *ret;
if (!mem || !size) return NULL;
if (!mem || !size) { return NULL; }
ALLOC_CHECK_SIZE(size);
ret = malloc(size);
@ -201,7 +201,7 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
u8 *ret;
if (!mem || !size) return NULL;
if (!mem || !size) { return NULL; }
ALLOC_CHECK_SIZE(size);
ret = malloc(size + 1);
@ -214,105 +214,104 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
}
/* In non-debug mode, we just do straightforward aliasing of the above functions
to user-visible names such as ck_alloc(). */
/* In non-debug mode, we just do straightforward aliasing of the above
functions to user-visible names such as ck_alloc(). */
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free
#define alloc_report()
#define alloc_report()
#else
// This is the original alloc-inl of stock afl
// This is the original alloc-inl of stock afl
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
#define alloc_printf(_str...) \
({ \
\
u8 *_tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \
snprintf((char *)_tmp, _len + 1, _str); \
_tmp; \
\
})
#define alloc_printf(_str...) \
({ \
\
u8 *_tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \
snprintf((char *)_tmp, _len + 1, _str); \
_tmp; \
\
})
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
#define ALLOC_CHECK_SIZE(_s) \
do { \
\
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0)
#define ALLOC_CHECK_SIZE(_s) \
do { \
\
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0)
/* Macro to check malloc() failures and the like. */
/* Macro to check malloc() failures and the like. */
#define ALLOC_CHECK_RESULT(_r, _s) \
do { \
\
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0)
#define ALLOC_CHECK_RESULT(_r, _s) \
do { \
\
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0)
/* Magic tokens used to mark used / freed chunks. */
/* Magic tokens used to mark used / freed chunks. */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
/* Positions of guard tokens in relation to the user-visible pointer. */
/* Positions of guard tokens in relation to the user-visible pointer. */
#define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
#define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
#define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
#define ALLOC_C1(_ptr) (((u32 *)(_ptr))[-2])
#define ALLOC_S(_ptr) (((u32 *)(_ptr))[-1])
#define ALLOC_C2(_ptr) (((u8 *)(_ptr))[ALLOC_S(_ptr)])
#define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
#define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
/* Allocator increments for ck_realloc_block(). */
/* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256
#define ALLOC_BLK_INC 256
/* Sanity-checking macros for pointers. */
/* Sanity-checking macros for pointers. */
#define CHECK_PTR(_p) \
do { \
\
if (_p) { \
\
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
\
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \
else \
ABORT("Corrupted head alloc canary."); \
\
} \
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
ABORT("Corrupted tail alloc canary."); \
\
} \
\
} while (0)
#define CHECK_PTR(_p) \
do { \
\
if (_p) { \
\
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
\
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \
else \
ABORT("Corrupted head alloc canary."); \
\
} \
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
ABORT("Corrupted tail alloc canary."); \
\
} \
\
} while (0)
#define CHECK_PTR_EXPR(_p) \
({ \
\
typeof(_p) _tmp = (_p); \
CHECK_PTR(_tmp); \
_tmp; \
\
})
#define CHECK_PTR_EXPR(_p) \
({ \
\
typeof(_p) _tmp = (_p); \
CHECK_PTR(_tmp); \
_tmp; \
\
})
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */
@ -358,13 +357,12 @@ static inline void DFL_ck_free(void *mem) {
if (!mem) return;
CHECK_PTR(mem);
#ifdef DEBUG_BUILD
#ifdef DEBUG_BUILD
/* Catch pointer issues sooner. */
memset(mem, 0xFF, ALLOC_S(mem));
#endif /* DEBUG_BUILD */
#endif /* DEBUG_BUILD */
ALLOC_C1(mem) = ALLOC_MAGIC_F;
@ -379,7 +377,7 @@ static inline void DFL_ck_free(void *mem) {
static inline void *DFL_ck_realloc(void *orig, u32 size) {
void *ret;
u32 old_size = 0;
u32 old_size = 0;
if (!size) {
@ -392,9 +390,9 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
CHECK_PTR(orig);
#ifndef DEBUG_BUILD
#ifndef DEBUG_BUILD
ALLOC_C1(orig) = ALLOC_MAGIC_F;
#endif /* !DEBUG_BUILD */
#endif /* !DEBUG_BUILD */
old_size = ALLOC_S(orig);
orig -= ALLOC_OFF_HEAD;
@ -405,12 +403,12 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
ALLOC_CHECK_SIZE(size);
#ifndef DEBUG_BUILD
#ifndef DEBUG_BUILD
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
#else
#else
/* Catch pointer issues sooner: force relocation and make sure that the
original buffer is wiped. */
@ -429,7 +427,7 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
}
#endif /* ^!DEBUG_BUILD */
#endif /* ^!DEBUG_BUILD */
ret += ALLOC_OFF_HEAD;
@ -448,7 +446,7 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) {
static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
#ifndef DEBUG_BUILD
#ifndef DEBUG_BUILD
if (orig) {
@ -460,7 +458,7 @@ static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
}
#endif /* !DEBUG_BUILD */
#endif /* !DEBUG_BUILD */
return DFL_ck_realloc(orig, size);
@ -471,7 +469,7 @@ static inline void *DFL_ck_realloc_block(void *orig, u32 size) {
static inline u8 *DFL_ck_strdup(u8 *str) {
void *ret;
u32 size;
u32 size;
if (!str) return NULL;
@ -540,30 +538,30 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) {
}
#ifndef DEBUG_BUILD
#ifndef DEBUG_BUILD
/* In non-debug mode, we just do straightforward aliasing of the above functions
to user-visible names such as ck_alloc(). */
/* In non-debug mode, we just do straightforward aliasing of the above
functions to user-visible names such as ck_alloc(). */
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free
#define alloc_report()
#define alloc_report()
#else
#else
/* In debugging mode, we also track allocations to detect memory leaks, and the
flow goes through one more layer of indirection. */
/* In debugging mode, we also track allocations to detect memory leaks, and
the flow goes through one more layer of indirection. */
/* Alloc tracking data structures: */
/* Alloc tracking data structures: */
#define ALLOC_BUCKETS 4096
#define ALLOC_BUCKETS 4096
struct TRK_obj {
@ -573,25 +571,25 @@ struct TRK_obj {
};
#ifdef AFL_MAIN
#ifdef AFL_MAIN
struct TRK_obj *TRK[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS];
#define alloc_report() TRK_report()
#define alloc_report() TRK_report()
#else
#else
extern struct TRK_obj *TRK[ALLOC_BUCKETS];
extern u32 TRK_cnt[ALLOC_BUCKETS];
#define alloc_report()
#define alloc_report()
#endif /* ^AFL_MAIN */
#endif /* ^AFL_MAIN */
/* Bucket-assigning function for a given pointer: */
/* Bucket-assigning function for a given pointer: */
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
/* Add a new entry to the list of allocated objects. */
@ -741,29 +739,30 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
}
/* Aliasing user-facing names to tracking functions: */
/* Aliasing user-facing names to tracking functions: */
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_alloc_nozero(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_alloc_nozero(_p1) \
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc(_p1, _p2) \
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc(_p1, _p2) \
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc_block(_p1, _p2) \
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc_block(_p1, _p2) \
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup(_p1, _p2) \
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup(_p1, _p2) \
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup_str(_p1, _p2) \
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup_str(_p1, _p2) \
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
#endif /* ^!DEBUG_BUILD */
#endif /* ^!DEBUG_BUILD */
#endif /* _WANT_ORIGINAL_AFL_ALLOC */
@ -772,8 +771,12 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func,
*/
static inline size_t next_pow2(size_t in) {
if (in == 0 || in > (size_t)-1)
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;
@ -794,10 +797,10 @@ static inline size_t next_pow2(size_t in) {
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;
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;
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
/* grow exponentially */
size_t next_size = next_pow2(size_needed);
@ -824,13 +827,13 @@ 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");
if (unlikely(size_needed < 1)) { FATAL("cannot grow to non-positive size"); }
/* No need to realloc */
if (likely(*size >= size_needed)) return *buf;
if (likely(*size >= size_needed)) { return *buf; }
/* No initial size was set */
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; }
/* grow exponentially */
size_t next_size = next_pow2(size_needed);

View File

@ -26,26 +26,29 @@
#ifndef _ANDROID_ASHMEM_H
#define _ANDROID_ASHMEM_H
#include <fcntl.h>
#include <linux/shm.h>
#include <linux/ashmem.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#ifdef __ANDROID__
#if __ANDROID_API__ >= 26
#define shmat bionic_shmat
#define shmctl bionic_shmctl
#define shmdt bionic_shmdt
#define shmget bionic_shmget
#endif
#include <sys/shm.h>
#undef shmat
#undef shmctl
#undef shmdt
#undef shmget
#include <stdio.h>
#include <fcntl.h>
#include <linux/shm.h>
#include <linux/ashmem.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define ASHMEM_DEVICE "/dev/ashmem"
#if __ANDROID_API__ >= 26
#define shmat bionic_shmat
#define shmctl bionic_shmctl
#define shmdt bionic_shmdt
#define shmget bionic_shmget
#endif
#include <sys/shm.h>
#undef shmat
#undef shmctl
#undef shmdt
#undef shmget
#include <stdio.h>
#define ASHMEM_DEVICE "/dev/ashmem"
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
@ -103,5 +106,7 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
}
#endif /* __ANDROID__ */
#endif

View File

@ -29,6 +29,7 @@
#define _AFL_CMPLOG_H
#include "config.h"
#include "forkserver.h"
#define CMP_MAP_W 65536
#define CMP_MAP_H 256
@ -74,5 +75,9 @@ struct cmp_map {
};
/* Execs the child */
void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv);
#endif

View File

@ -51,6 +51,16 @@ char * get_afl_env(char *env);
extern u8 be_quiet;
extern u8 *doc_path; /* path to documentation dir */
/* Find binary, used by analyze, showmap, tmin
@returns the path, allocating the string */
u8 *find_binary(u8 *fname);
/* Read a bitmap from file fname to memory
This is for the -B option again. */
void read_bitmap(u8 *fname, u8 *map, size_t len);
/* Get unix time in milliseconds */
u64 get_cur_time(void);
@ -99,9 +109,13 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
/* Wrapper for select() and read(), reading exactly len bytes.
Returns the time passed to read.
stop_soon should point to a variable indicating ctrl+c was pressed.
If the wait times out, returns timeout_ms + 1;
Returns 0 if an error occurred (fd closed, signal, ...); */
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms);
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
volatile u8 *stop_soon_p);
u32 get_map_size(void);
#endif

View File

@ -28,7 +28,7 @@
/* Version string: */
// c = release, d = volatile github dev, e = experimental branch
#define VERSION "++2.63c"
#define VERSION "++2.65c"
/******************************************************
* *
@ -49,7 +49,7 @@
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
#define FANCY_BOXES
#define FANCY_BOXES
#endif
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
@ -63,20 +63,20 @@
/* 64bit arch MACRO */
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
#define WORD_SIZE_64 1
#define WORD_SIZE_64 1
#endif
/* Default memory limit for child process (MB): */
#ifndef __NetBSD__
#ifndef WORD_SIZE_64
#define MEM_LIMIT 25
#else
#define MEM_LIMIT 50
#endif /* ^!WORD_SIZE_64 */
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
#165 */
#define MEM_LIMIT 200
#ifndef WORD_SIZE_64
#define MEM_LIMIT 25
#else
#define MEM_LIMIT 50
#endif /* ^!WORD_SIZE_64 */
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
#165 */
#define MEM_LIMIT 200
#endif
/* Default memory limit when running in QEMU mode (MB): */
@ -201,8 +201,8 @@
(first value), and to keep in memory as candidates. The latter should be much
higher than the former. */
#define USE_AUTO_EXTRAS 50
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
#define USE_AUTO_EXTRAS 128
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64)
/* Scaling factor for the effector map used to skip some of the more
expensive deterministic steps. The actual divisor is set to
@ -395,9 +395,9 @@
/* for *BSD: use ARC4RANDOM and save a file descriptor */
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#ifndef HAVE_ARC4RANDOM
#define HAVE_ARC4RANDOM 1
#endif
#ifndef HAVE_ARC4RANDOM
#define HAVE_ARC4RANDOM 1
#endif
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
#endif /* ! _HAVE_CONFIG_H */

View File

@ -28,87 +28,92 @@
#include "types.h"
#include "config.h"
/* __FUNCTION__ is non-iso */
#ifdef __func__
#define __FUNCTION__ __func__
#endif
/*******************
* Terminal colors *
*******************/
#ifndef MESSAGES_TO_STDOUT
#define MESSAGES_TO_STDOUT
#define MESSAGES_TO_STDOUT
#endif
#ifdef USE_COLOR
#define cBLK "\x1b[0;30m"
#define cRED "\x1b[0;31m"
#define cGRN "\x1b[0;32m"
#define cBRN "\x1b[0;33m"
#define cBLU "\x1b[0;34m"
#define cMGN "\x1b[0;35m"
#define cCYA "\x1b[0;36m"
#define cLGR "\x1b[0;37m"
#define cGRA "\x1b[1;90m"
#define cLRD "\x1b[1;91m"
#define cLGN "\x1b[1;92m"
#define cYEL "\x1b[1;93m"
#define cLBL "\x1b[1;94m"
#define cPIN "\x1b[1;95m"
#define cLCY "\x1b[1;96m"
#define cBRI "\x1b[1;97m"
#define cRST "\x1b[0m"
#define cBLK "\x1b[0;30m"
#define cRED "\x1b[0;31m"
#define cGRN "\x1b[0;32m"
#define cBRN "\x1b[0;33m"
#define cBLU "\x1b[0;34m"
#define cMGN "\x1b[0;35m"
#define cCYA "\x1b[0;36m"
#define cLGR "\x1b[0;37m"
#define cGRA "\x1b[1;90m"
#define cLRD "\x1b[1;91m"
#define cLGN "\x1b[1;92m"
#define cYEL "\x1b[1;93m"
#define cLBL "\x1b[1;94m"
#define cPIN "\x1b[1;95m"
#define cLCY "\x1b[1;96m"
#define cBRI "\x1b[1;97m"
#define cRST "\x1b[0m"
#define bgBLK "\x1b[40m"
#define bgRED "\x1b[41m"
#define bgGRN "\x1b[42m"
#define bgBRN "\x1b[43m"
#define bgBLU "\x1b[44m"
#define bgMGN "\x1b[45m"
#define bgCYA "\x1b[46m"
#define bgLGR "\x1b[47m"
#define bgGRA "\x1b[100m"
#define bgLRD "\x1b[101m"
#define bgLGN "\x1b[102m"
#define bgYEL "\x1b[103m"
#define bgLBL "\x1b[104m"
#define bgPIN "\x1b[105m"
#define bgLCY "\x1b[106m"
#define bgBRI "\x1b[107m"
#define bgBLK "\x1b[40m"
#define bgRED "\x1b[41m"
#define bgGRN "\x1b[42m"
#define bgBRN "\x1b[43m"
#define bgBLU "\x1b[44m"
#define bgMGN "\x1b[45m"
#define bgCYA "\x1b[46m"
#define bgLGR "\x1b[47m"
#define bgGRA "\x1b[100m"
#define bgLRD "\x1b[101m"
#define bgLGN "\x1b[102m"
#define bgYEL "\x1b[103m"
#define bgLBL "\x1b[104m"
#define bgPIN "\x1b[105m"
#define bgLCY "\x1b[106m"
#define bgBRI "\x1b[107m"
#else
#define cBLK ""
#define cRED ""
#define cGRN ""
#define cBRN ""
#define cBLU ""
#define cMGN ""
#define cCYA ""
#define cLGR ""
#define cGRA ""
#define cLRD ""
#define cLGN ""
#define cYEL ""
#define cLBL ""
#define cPIN ""
#define cLCY ""
#define cBRI ""
#define cRST ""
#define cBLK ""
#define cRED ""
#define cGRN ""
#define cBRN ""
#define cBLU ""
#define cMGN ""
#define cCYA ""
#define cLGR ""
#define cGRA ""
#define cLRD ""
#define cLGN ""
#define cYEL ""
#define cLBL ""
#define cPIN ""
#define cLCY ""
#define cBRI ""
#define cRST ""
#define bgBLK ""
#define bgRED ""
#define bgGRN ""
#define bgBRN ""
#define bgBLU ""
#define bgMGN ""
#define bgCYA ""
#define bgLGR ""
#define bgGRA ""
#define bgLRD ""
#define bgLGN ""
#define bgYEL ""
#define bgLBL ""
#define bgPIN ""
#define bgLCY ""
#define bgBRI ""
#define bgBLK ""
#define bgRED ""
#define bgGRN ""
#define bgBRN ""
#define bgBLU ""
#define bgMGN ""
#define bgCYA ""
#define bgLGR ""
#define bgGRA ""
#define bgLRD ""
#define bgLGN ""
#define bgYEL ""
#define bgLBL ""
#define bgPIN ""
#define bgLCY ""
#define bgBRI ""
#endif /* ^USE_COLOR */
@ -118,39 +123,39 @@
#ifdef FANCY_BOXES
#define SET_G1 "\x1b)0" /* Set G1 for box drawing */
#define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
#define bSTART "\x0e" /* Enter G1 drawing mode */
#define bSTOP "\x0f" /* Leave G1 drawing mode */
#define bH "q" /* Horizontal line */
#define bV "x" /* Vertical line */
#define bLT "l" /* Left top corner */
#define bRT "k" /* Right top corner */
#define bLB "m" /* Left bottom corner */
#define bRB "j" /* Right bottom corner */
#define bX "n" /* Cross */
#define bVR "t" /* Vertical, branch right */
#define bVL "u" /* Vertical, branch left */
#define bHT "v" /* Horizontal, branch top */
#define bHB "w" /* Horizontal, branch bottom */
#define SET_G1 "\x1b)0" /* Set G1 for box drawing */
#define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
#define bSTART "\x0e" /* Enter G1 drawing mode */
#define bSTOP "\x0f" /* Leave G1 drawing mode */
#define bH "q" /* Horizontal line */
#define bV "x" /* Vertical line */
#define bLT "l" /* Left top corner */
#define bRT "k" /* Right top corner */
#define bLB "m" /* Left bottom corner */
#define bRB "j" /* Right bottom corner */
#define bX "n" /* Cross */
#define bVR "t" /* Vertical, branch right */
#define bVL "u" /* Vertical, branch left */
#define bHT "v" /* Horizontal, branch top */
#define bHB "w" /* Horizontal, branch bottom */
#else
#define SET_G1 ""
#define RESET_G1 ""
#define bSTART ""
#define bSTOP ""
#define bH "-"
#define bV "|"
#define bLT "+"
#define bRT "+"
#define bLB "+"
#define bRB "+"
#define bX "+"
#define bVR "+"
#define bVL "+"
#define bHT "+"
#define bHB "+"
#define SET_G1 ""
#define RESET_G1 ""
#define bSTART ""
#define bSTOP ""
#define bH "-"
#define bV "|"
#define bLT "+"
#define bRT "+"
#define bLB "+"
#define bRB "+"
#define bX "+"
#define bVR "+"
#define bVL "+"
#define bHT "+"
#define bHB "+"
#endif /* ^FANCY_BOXES */
@ -171,9 +176,9 @@
/* Just print stuff to the appropriate stream. */
#ifdef MESSAGES_TO_STDOUT
#define SAYF(x...) printf(x)
#define SAYF(x...) printf(x)
#else
#define SAYF(x...) fprintf(stderr, x)
#define SAYF(x...) fprintf(stderr, x)
#endif /* ^MESSAGES_TO_STDOUT */
/* Show a prefixed warning. */

View File

@ -29,6 +29,9 @@
#define __AFL_FORKSERVER_H
#include <stdio.h>
#include <stdbool.h>
#include "types.h"
typedef struct afl_forkserver {
@ -40,6 +43,7 @@ typedef struct afl_forkserver {
s32 fsrv_pid, /* PID of the fork server */
child_pid, /* PID of the fuzzed program */
child_status, /* waitpid result for the child */
out_dir_fd; /* FD of the lock file */
s32 out_fd, /* Persistent fd for fsrv->out_file */
@ -50,42 +54,76 @@ typedef struct afl_forkserver {
fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */
u8 no_unlink; /* do not unlink cur_input */
u32 exec_tmout; /* Configurable exec timeout (ms) */
u32 map_size; /* map size used by the target */
u32 snapshot; /* is snapshot feature used */
u64 mem_limit; /* Memory cap for child (MB) */
u64 total_execs; /* How often run_target was called */
u8 *out_file, /* File to fuzz, if any */
*target_path; /* Path of the target */
*target_path; /* Path of the target */
FILE *plot_file; /* Gnuplot output file */
u8 child_timed_out; /* Traced process timed out? */
/* Note: lat_run_timed_out is u32 to send it to the child as 4 byte array */
u32 last_run_timed_out; /* Traced process timed out? */
u8 last_kill_signal; /* Signal that killed the child */
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
u32 prev_timed_out; /* if prev forkserver run timed out */
u8 qemu_mode; /* if running in qemu mode or not */
char *cmplog_binary; /* the name of the cmplog binary */
/* Function to kick off the forkserver child */
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
u8 *function_opt; /* for autodictionary: afl ptr */
void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len);
} afl_forkserver_t;
typedef enum fsrv_run_result {
/* 00 */ FSRV_RUN_OK = 0,
/* 01 */ FSRV_RUN_TMOUT,
/* 02 */ FSRV_RUN_CRASH,
/* 03 */ FSRV_RUN_ERROR,
/* 04 */ FSRV_RUN_NOINST,
/* 05 */ FSRV_RUN_NOBITS,
} fsrv_run_result_t;
void afl_fsrv_init(afl_forkserver_t *fsrv);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv);
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
void afl_fsrv_killall();
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output);
void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len);
fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
volatile u8 *stop_soon_p);
void afl_fsrv_killall(void);
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
#ifdef __APPLE__
#define MSG_FORK_ON_APPLE \
" - On MacOS X, the semantics of fork() syscalls are non-standard and " \
"may\n" \
" break afl-fuzz performance optimizations when running " \
"platform-specific\n" \
" targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
#define MSG_FORK_ON_APPLE \
" - On MacOS X, the semantics of fork() syscalls are non-standard and " \
"may\n" \
" break afl-fuzz performance optimizations when running " \
"platform-specific\n" \
" targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
#else
#define MSG_FORK_ON_APPLE ""
#define MSG_FORK_ON_APPLE ""
#endif
#ifdef RLIMIT_AS
#define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
#define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
#else
#define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
#define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
#endif /* ^RLIMIT_AS */
#endif

View File

@ -32,7 +32,7 @@
#ifdef __x86_64__
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
static inline u32 hash32(const void *key, u32 len, u32 seed) {
@ -67,7 +67,7 @@ static inline u32 hash32(const void *key, u32 len, u32 seed) {
#else
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
static inline u32 hash32(const void *key, u32 len, u32 seed) {

View File

@ -50,7 +50,7 @@ typedef struct list_element {
typedef struct list {
element_t element_prealloc_buf[LIST_PREALLOC_SIZE];
u32 element_prealloc_count;
s32 element_prealloc_count;
} list_t;
@ -83,7 +83,7 @@ static inline void list_append(list_t *list, void *el) {
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");
if (!el_box) { FATAL("failed to allocate list element"); }
el_box->data = el;
el_box->next = head;
el_box->prev = head->prev;

View File

@ -28,6 +28,8 @@
#ifndef __AFL_SHAREDMEM_H
#define __AFL_SHAREDMEM_H
#include "types.h"
typedef struct sharedmem {
// extern unsigned char *trace_bits;
@ -44,8 +46,7 @@ typedef struct sharedmem {
u8 *map; /* shared memory region */
size_t size_alloc; /* actual allocated size */
size_t size_used; /* in use by shmem app */
size_t map_size; /* actual allocated size */
int cmplog_mode;
struct cmp_map *cmp_map;

View File

@ -30,6 +30,29 @@ typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
/* Extended forkserver option values */
/* Reporting errors */
#define FS_OPT_ERROR 0xf800008f
#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
#define FS_ERROR_MAP_SIZE 1
#define FS_ERROR_MAP_ADDR 2
#define FS_ERROR_SHM_OPEN 4
#define FS_ERROR_SHMAT 8
#define FS_ERROR_MMAP 16
/* Reporting options */
#define FS_OPT_ENABLED 0x8f000001
#define FS_OPT_MAPSIZE 0x40000000
#define FS_OPT_SNAPSHOT 0x20000000
#define FS_OPT_AUTODICT 0x10000000
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
#define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1)
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
#define FS_OPT_SET_MAPSIZE(x) \
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
/*
Ugh. There is an unintended compiler / glibc #include glitch caused by
@ -46,7 +69,7 @@ typedef uint32_t u32;
*/
#ifdef __x86_64__
#if defined(__x86_64__) || defined(__aarch64__)
typedef unsigned long long u64;
#else
typedef uint64_t u64;
@ -58,22 +81,24 @@ typedef int32_t s32;
typedef int64_t s64;
#ifndef MIN
#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; \
\
})
#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) \
@ -108,21 +133,21 @@ typedef int64_t s64;
})
#ifdef AFL_LLVM_PASS
#if defined(__linux__)
#define AFL_SR(s) (srandom(s))
#define AFL_R(x) (random() % (x))
#if defined(__linux__) || !defined(__ANDROID__)
#define AFL_SR(s) (srandom(s))
#define AFL_R(x) (random() % (x))
#else
#define AFL_SR(s) ((void)s)
#define AFL_R(x) (arc4random_uniform(x))
#endif
#else
#define AFL_SR(s) ((void)s)
#define AFL_R(x) (arc4random_uniform(x))
#endif
#else
#if defined(__linux__)
#define SR(s) (srandom(s))
#define R(x) (random() % (x))
#else
#define SR(s) ((void)s)
#define R(x) (arc4random_uniform(x))
#endif
#if defined(__linux__) || !defined(__ANDROID__)
#define SR(s) (srandom(s))
#define R(x) (random() % (x))
#else
#define SR(s) ((void)s)
#define R(x) (arc4random_uniform(x))
#endif
#endif /* ^AFL_LLVM_PASS */
#define STRINGIFY_INTERNAL(x) #x
@ -131,15 +156,19 @@ typedef int64_t s64;
#define MEM_BARRIER() __asm__ volatile("" ::: "memory")
#if __GNUC__ < 6
#define likely(_x) (_x)
#define unlikely(_x) (_x)
#ifndef likely
#define likely(_x) (_x)
#endif
#ifndef unlikely
#define unlikely(_x) (_x)
#endif
#else
#ifndef likely
#define likely(_x) __builtin_expect(!!(_x), 1)
#endif
#ifndef unlikely
#define unlikely(_x) __builtin_expect(!!(_x), 0)
#endif
#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

@ -39,5 +39,5 @@ clean:
install: all
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
install -m 755 ../libdislocator.so $${DESTDIR}$(HELPER_PATH)
install -m 644 README.dislocator.md $${DESTDIR}$(HELPER_PATH)
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md

View File

@ -30,39 +30,39 @@
#include <sys/mman.h>
#ifdef __APPLE__
#include <mach/vm_statistics.h>
#include <mach/vm_statistics.h>
#endif
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/param.h>
#endif
#ifdef __linux__
#include <unistd.h>
#include <sys/syscall.h>
#ifdef __NR_getrandom
#define arc4random_buf(p, l) \
do { \
\
ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
if (rd != l) DEBUGF("getrandom failed"); \
\
} while (0)
#if defined(__linux__) && !defined(__ANDROID__)
#include <unistd.h>
#include <sys/syscall.h>
#ifdef __NR_getrandom
#define arc4random_buf(p, l) \
do { \
\
ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
if (rd != l) DEBUGF("getrandom failed"); \
\
} while (0)
#else
#include <time.h>
#define arc4random_buf(p, l) \
do { \
\
srand(time(NULL)); \
u32 i; \
u8 *ptr = (u8 *)p; \
for (i = 0; i < l; i++) \
ptr[i] = rand() % INT_MAX; \
\
} while (0)
#else
#include <time.h>
#define arc4random_buf(p, l) \
do { \
\
srand(time(NULL)); \
u32 i; \
u8 *ptr = (u8 *)p; \
for (i = 0; i < l; i++) \
ptr[i] = rand() % INT_MAX; \
\
} while (0)
#endif
#endif
#endif
#include "config.h"
@ -83,11 +83,11 @@ typedef struct {
#define ALLOC_ALIGN_SIZE (_Alignof(max_align_t))
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#define PAGE_SIZE 4096
#endif /* !PAGE_SIZE */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#define MAP_ANONYMOUS MAP_ANON
#endif /* !MAP_ANONYMOUS */
#define SUPER_PAGE_SIZE 1 << 21
@ -148,8 +148,8 @@ static u8 alloc_verbose, /* Additional debug messages */
align_allocations; /* Force alignment to sizeof(void*) */
#if defined __OpenBSD__ || defined __APPLE__
#define __thread
#warning no thread support available
#define __thread
#warning no thread support available
#endif
static __thread size_t total_mem; /* Currently allocated mem */
@ -183,38 +183,38 @@ static void *__dislocator_alloc(size_t len) {
else
rlen = len;
/* We will also store buffer length and a canary below the actual buffer, so
let's add 8 bytes for that. */
tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
flags = MAP_PRIVATE | MAP_ANONYMOUS;
fd = -1;
#if defined(USEHUGEPAGE)
sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
#if defined(__APPLE__)
#if defined(__APPLE__)
if (sp) fd = VM_FLAGS_SUPERPAGE_SIZE_2MB;
#elif defined(__linux__)
#elif defined(__linux__)
if (sp) flags |= MAP_HUGETLB;
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__)
if (sp) flags |= MAP_ALIGNED_SUPER;
#endif
#endif
#else
(void)sp;
#endif
/* We will also store buffer length and a canary below the actual buffer, so
let's add 8 bytes for that. */
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
#if defined(USEHUGEPAGE)
/* We try one more time with regular call */
if (ret == MAP_FAILED) {
#if defined(__APPLE__)
#if defined(__APPLE__)
fd = -1;
#elif defined(__linux__)
#elif defined(__linux__)
flags &= -MAP_HUGETLB;
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__)
flags &= -MAP_ALIGNED_SUPER;
#endif
#endif
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
}
@ -296,10 +296,6 @@ void *calloc(size_t elem_len, size_t elem_cnt) {
}
/* TODO: add a wrapper for posix_memalign, otherwise apps who use it,
will fail when freeing the memory.
*/
/* The wrapper for malloc(). Roughly the same, also clobbers the returned
memory (unlike calloc(), malloc() is not guaranteed to return zeroed
memory). */
@ -468,6 +464,18 @@ void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
}
#if !defined(__ANDROID__)
size_t malloc_usable_size(void *ptr) {
#else
size_t malloc_usable_size(const void *ptr) {
#endif
return ptr ? PTR_L(ptr) : 0;
}
__attribute__((constructor)) void __dislocator_init(void) {
u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB");

View File

@ -1,63 +0,0 @@
#
# 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

@ -21,7 +21,7 @@
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
@ -35,18 +35,20 @@
#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && \
!defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__
#error "Sorry, this library is unsupported in this platform for now!"
#error "Sorry, this library is unsupported in this platform for now!"
#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
!__NetBSD__*/
#if defined __APPLE__
#include <mach/vm_map.h>
#include <mach/mach_init.h>
#include <mach/vm_map.h>
#include <mach/mach_init.h>
#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#if !defined __NetBSD__
#include <sys/user.h>
#endif
#include <sys/mman.h>
#endif
#include <dlfcn.h>
@ -152,25 +154,25 @@ static void __tokencap_load_mappings(void) {
#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
#if defined __FreeBSD__
#if defined __FreeBSD__
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid};
#elif defined __OpenBSD__
#elif defined __OpenBSD__
int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid};
#elif defined __NetBSD__
#elif defined __NetBSD__
int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid,
sizeof(struct kinfo_vmentry)};
#endif
#endif
char * buf, *low, *high;
size_t miblen = sizeof(mib) / sizeof(mib[0]);
size_t len;
if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return;
#if defined __FreeBSD__ || defined __NetBSD__
#if defined __FreeBSD__ || defined __NetBSD__
len = len * 4 / 3;
#elif defined __OpenBSD__
#elif defined __OpenBSD__
len -= len % sizeof(struct kinfo_vmentry);
#endif
#endif
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (buf == MAP_FAILED) return;
@ -191,22 +193,22 @@ static void __tokencap_load_mappings(void) {
struct kinfo_vmentry *region = (struct kinfo_vmentry *)low;
#if defined __FreeBSD__ || defined __NetBSD__
#if defined __FreeBSD__ || defined __NetBSD__
#if defined __FreeBSD__
#if defined __FreeBSD__
size_t size = region->kve_structsize;
if (size == 0) break;
#elif defined __NetBSD__
#elif defined __NetBSD__
size_t size = sizeof(*region);
#endif
#endif
/* We go through the whole mapping of the process and track read-only
* addresses */
if ((region->kve_protection & KVME_PROT_READ) &&
!(region->kve_protection & KVME_PROT_WRITE)) {
#elif defined __OpenBSD__
#elif defined __OpenBSD__
size_t size = sizeof(*region);
@ -215,7 +217,7 @@ static void __tokencap_load_mappings(void) {
if ((region->kve_protection & KVE_PROT_READ) &&
!(region->kve_protection & KVE_PROT_WRITE)) {
#endif
#endif
__tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start;
__tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end;
@ -274,7 +276,8 @@ static void __tokencap_dump(const u8 *ptr, size_t len, u8 is_text) {
pos += 4;
break;
default: buf[pos++] = ptr[i];
default:
buf[pos++] = ptr[i];
}

View File

@ -1,4 +1,3 @@
#
# american fuzzy lop++ - LLVM instrumentation
# -----------------------------------------
#
@ -39,13 +38,14 @@ 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 )
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
LLVM_STDCXX = gnu++11
LLVM_APPLE = $(shell clang -v 2>&1 | grep -iq apple && echo 1 || echo 0)
LLVM_APPLE_XCODE = $(shell clang -v 2>&1 | grep -q Apple && echo 1 || echo 0)
LLVM_LTO = 0
ifeq "$(LLVMVER)" ""
@ -58,22 +58,24 @@ 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
endif
ifeq "$(LLVM_MAJOR)" "11"
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
LLVM_LTO = 1
TEST_MMAP = 1
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 9, afl-clang-lto LTO will not be build.)
$(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE)" "1"
ifeq "$(LLVM_APPLE_XCODE)" "1"
$(warning llvm_mode will not compile with Xcode clang...)
endif
@ -84,27 +86,76 @@ endif
CC = $(LLVM_BINDIR)/clang
CXX = $(LLVM_BINDIR)/clang++
# llvm-config --bindir may not providing a valid path, so ...
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
# 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++
# however we must ensure that this is not a "CC=gcc make"
ifeq "$(shell command -v $(CC) 2> /dev/null)" ""
# we do not have a valid CC variable so we try alternatives
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
# we found one in the local install directory, lets use these
CC = $(BIN_DIR)/clang
else
# hope for the best
$(warning we have trouble finding clang - llvm-config is not helping us)
CC = clang
endif
endif
endif
# llvm-config --bindir may not providing a valid path, so ...
ifeq "$(shell test -e $(CXX) || echo 1 )" "1"
# however we must ensure that this is not a "CC=gcc make"
ifeq "$(shell command -v $(CXX) 2> /dev/null)" ""
# we do not have a valid CC variable so we try alternatives
ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1"
# we found one in the local install directory, lets use these
CXX = $(BIN_DIR)/clang++
else
# hope for the best
$(warning we have trouble finding clang++ - llvm-config is not helping us)
CXX = clang++
endif
endif
endif
# sanity check.
# Are versions of clang --version and llvm-config --version equal?
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
ifneq "$(CLANGVER)" "$(LLVMVER)"
CC = $(shell $(LLVM_CONFIG) --bindir)/clang
CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++
# I disable this because it does not make sense with what we did before (marc)
# We did exactly set these 26 lines above with these values, and it would break
# "CC=gcc make" etc. usages
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
CC_SAVE := $(LLVM_BINDIR)/clang
else
CC_SAVE := $(CC)
endif
ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" ""
CXX_SAVE := $(LLVM_BINDIR)/clang++
else
CXX_SAVE := $(CXX)
endif
CLANG_BIN := $(CC_SAVE)
CLANGPP_BIN := $(CXX_SAVE)
ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang"
USE_BINDIR = 1
else
ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++"
USE_BINDIR = 1
else
USE_BINDIR = 0
endif
endif
# On old platform we cannot compile with clang because std++ libraries are too
# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX
# variable we override the compiler variables here
ifneq "$(REAL_CC)" ""
CC = $(REAL_CC)
endif
ifneq "$(REAL_CXX)" ""
CXX = $(REAL_CXX)
endif
# After we set CC/CXX we can start makefile magic tests
@ -113,41 +164,47 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .te
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"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto=full
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto
endif
endif
endif
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)
ifeq "$(LLVM_LTO)" "1"
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(AFL_REAL_LD)" ""
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
else
$(warn ld.lld not found, can not enable LTO mode)
LLVM_LTO = 0
endif
endif
endif
endif
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"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FUSELD=1
endif
endif
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
override CFLAGS = -Wall \
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
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
ifdef AFL_TRACE_PC
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
endif
@ -156,13 +213,15 @@ 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_CFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fpic $(CXXFLAGS)
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(shell uname)" "Darwin"
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
else
CLANG_CFL += -Wl,-znodelete
endif
ifeq "$(shell uname)" "OpenBSD"
@ -174,23 +233,23 @@ ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int ma
else
SHMAT_OK=0
CFLAGS+=-DUSEMMAP=1
LDFLAGS += -lrt
LDFLAGS += -Wno-deprecated-declarations
endif
ifeq "$(TEST_MMAP)" "1"
SHMAT_OK=0
CFLAGS+=-DUSEMMAP=1
LDFLAGS += -lrt
LDFLAGS += -Wno-deprecated-declarations
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
PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
# If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" ""
NO_BUILD = 1
endif
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE)" "00"
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
NO_BUILD = 1
endif
@ -222,7 +281,7 @@ no_build:
test_deps:
@echo "[*] Checking for working 'llvm-config'..."
ifneq "$(LLVM_APPLE)" "1"
ifneq "$(LLVM_APPLE_XCODE)" "1"
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 )
endif
@echo "[*] Checking for working '$(CC)'..."
@ -230,7 +289,6 @@ test_deps:
@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
@ -242,7 +300,7 @@ 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)\"
$(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -Dxxx
ln -sf afl-clang-fast ../afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@ -251,64 +309,65 @@ ifeq "$(LLVM_LTO)" "1"
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-common.o: afl-llvm-common.cc afl-llvm-common.h
$(CXX) $(CFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps
../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc afl-llvm-common.o | test_deps
-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
../afl-llvm-pass.so: afl-llvm-pass.so.cc afl-llvm-common.o | test_deps
ifeq "$(LLVM_MIN_4_0_1)" "0"
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
endif
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc
../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
endif
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc MarkNodes.cc
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
@$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
endif
../afl-llvm-lto-instrim.so: afl-llvm-lto-instrim.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o
endif
# laf
../split-switches-pass.so: split-switches-pass.so.cc | 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)
../split-switches-pass.so: split-switches-pass.so.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
../compare-transform-pass.so: compare-transform-pass.so.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
../split-compares-pass.so: split-compares-pass.so.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
# /laf
../cmplog-routines-pass.so: cmplog-routines-pass.cc | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
../cmplog-routines-pass.so: cmplog-routines-pass.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
$(CC) $(CFLAGS) -fPIC -c $< -o $@
$(CC) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC) $(CFLAGS) -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CC) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CFLAGS) -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CC) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_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)
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS)
ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr
@ -323,7 +382,7 @@ all_done: test_build
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-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
@ -363,4 +422,4 @@ 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
rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld ../afl-ld ../afl-llvm-rt*.o

View File

@ -12,13 +12,13 @@ typedef long double max_align_t;
#include "llvm/ADT/DenseSet.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Support/CFG.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/DebugInfo.h"
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
@ -36,11 +36,13 @@ typedef long double max_align_t;
#include <string>
#include <fstream>
#include "MarkNodes.h"
#include "afl-llvm-common.h"
#include "llvm-ngram-coverage.h"
#include "config.h"
#include "debug.h"
#include "MarkNodes.h"
using namespace llvm;
static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
@ -53,9 +55,9 @@ namespace {
struct InsTrim : public ModulePass {
protected:
std::list<std::string> myWhitelist;
uint32_t function_minimum_size = 1;
uint32_t debug = 0;
uint32_t function_minimum_size = 1;
uint32_t debug = 0;
char * skip_nozero = NULL;
private:
std::mt19937 generator;
@ -69,24 +71,10 @@ struct InsTrim : public ModulePass {
public:
static char ID;
InsTrim() : ModulePass(ID), generator(0) {
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
if (instWhiteListFilename) {
std::string line;
std::ifstream fileStream;
fileStream.open(instWhiteListFilename);
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
getline(fileStream, line);
while (fileStream) {
myWhitelist.push_back(line);
getline(fileStream, line);
}
}
initWhitelist();
}
@ -107,27 +95,10 @@ struct InsTrim : public ModulePass {
}
// ripped from aflgo
static bool isBlacklisted(const Function *F) {
static const char *Blacklist[] = {
"asan.",
"llvm.",
"sancov.",
"__ubsan_handle_",
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
}
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
#define AFL_HAVE_VECTOR_INTRINSICS 1
#endif
bool runOnModule(Module &M) override {
@ -143,11 +114,17 @@ struct InsTrim : public ModulePass {
if (getenv("AFL_DEBUG") != NULL) debug = 1;
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str;
if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n");
#endif
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
getenv("LOOPHEAD") != NULL) {
@ -156,27 +133,124 @@ struct InsTrim : public ModulePass {
}
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL)
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
unsigned int PrevLocSize = 0;
char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
char *ctx_str = getenv("AFL_LLVM_CTX");
#ifdef AFL_HAVE_VECTOR_INTRINSICS
unsigned int ngram_size = 0;
/* Decide previous location vector size (must be a power of two) */
VectorType *PrevLocTy;
if (ngram_size_str)
if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 ||
ngram_size > NGRAM_SIZE_MAX)
FATAL(
"Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX "
"(%u))",
NGRAM_SIZE_MAX);
if (ngram_size)
PrevLocSize = ngram_size - 1;
else
#else
if (ngram_size_str)
#ifdef LLVM_VERSION_STRING
FATAL(
"Sorry, NGRAM branch coverage is not supported with llvm version %s!",
LLVM_VERSION_STRING);
#else
#ifndef LLVM_VERSION_PATCH
FATAL(
"Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
#else
FATAL(
"Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH);
#endif
#endif
#endif
PrevLocSize = 1;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
// IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
IntegerType *IntLocTy =
IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT);
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize);
#endif
/* Get globals for the SHM region and the previous location. Note that
__afl_prev_loc is thread-local. */
GlobalVariable *AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
GlobalVariable *AFLPrevLoc;
GlobalVariable *AFLContext;
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
if (ctx_str)
#ifdef __ANDROID__
AFLContext = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
#else
AFLContext = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx",
0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
#ifdef __ANDROID__
AFLPrevLoc = new GlobalVariable(
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_loc");
#else
AFLPrevLoc = new GlobalVariable(
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_loc",
/* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
/* AddressSpace */ 0, /* IsExternallyInitialized */ false);
#endif
else
#endif
#ifdef __ANDROID__
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
#else
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif
#ifdef AFL_HAVE_VECTOR_INTRINSICS
/* Create the vector shuffle mask for updating the previous block history.
Note that the first element of the vector will store cur_loc, so just set
it to undef to allow the optimizer to do its thing. */
SmallVector<Constant *, 32> PrevLocShuffle = {UndefValue::get(Int32Ty)};
for (unsigned I = 0; I < PrevLocSize - 1; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I));
for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I)
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
#endif
// this is our default
MarkSetOpt = true;
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
GlobalVariable *CovMapPtr = new GlobalVariable(
M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage,
nullptr, "__afl_area_ptr");
GlobalVariable *OldPrev = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
GlobalVariable::GeneralDynamicTLSModel, 0, false);
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
ConstantInt *One32 = ConstantInt::get(Int32Ty, 1);
u64 total_rs = 0;
u64 total_hs = 0;
@ -194,138 +268,11 @@ struct InsTrim : public ModulePass {
}
if (!isInWhitelist(&F)) continue;
// if the function below our minimum size skip it (1 or 2)
if (F.size() < function_minimum_size) { continue; }
if (!myWhitelist.empty()) {
bool instrumentBlock = false;
DebugLoc Loc;
StringRef instFilename;
unsigned int instLine = 0;
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (!Loc) Loc = IP->getDebugLoc();
}
if (Loc) {
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
instLine = cDILoc->getLine();
instFilename = cDILoc->getFilename();
if (instFilename.str().empty()) {
/* If the original location is empty, try using the inlined location
*/
DILocation *oDILoc = cDILoc->getInlinedAt();
if (oDILoc) {
instFilename = oDILoc->getFilename();
instLine = oDILoc->getLine();
}
}
/* Continue only if we know where we actually are */
if (!instFilename.str().empty()) {
for (std::list<std::string>::iterator it = myWhitelist.begin();
it != myWhitelist.end(); ++it) {
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(
instFilename.str().length() - it->length(),
it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
#else
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (Loc.isUnknown()) Loc = IP->getDebugLoc();
}
if (!Loc.isUnknown()) {
DILocation cDILoc(Loc.getAsMDNode(C));
instLine = cDILoc.getLineNumber();
instFilename = cDILoc.getFilename();
/* Continue only if we know where we actually are */
if (!instFilename.str().empty()) {
for (std::list<std::string>::iterator it = myWhitelist.begin();
it != myWhitelist.end(); ++it) {
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(
instFilename.str().length() - it->length(),
it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
#endif
/* Either we couldn't figure out our location or the location is
* not whitelisted, so we skip instrumentation. */
if (!instrumentBlock) {
if (!be_quiet) {
if (!instFilename.str().empty())
SAYF(cYEL "[!] " cBRI
"Not in whitelist, skipping %s line %u...\n",
instFilename.str().c_str(), instLine);
else
SAYF(cYEL "[!] " cBRI
"No filename information found, skipping it");
}
continue;
}
}
if (isBlacklisted(&F)) continue;
std::unordered_set<BasicBlock *> MS;
if (!MarkSetOpt) {
@ -401,13 +348,34 @@ struct InsTrim : public ModulePass {
}
if (function_minimum_size < 2) {
for (BasicBlock &BB : F) {
for (BasicBlock &BB : F) {
if (MS.find(&BB) == MS.end()) { continue; }
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
if (MS.find(&BB) == MS.end()) { continue; }
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev);
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size) {
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
PrevLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
Value *UpdatedPrevLoc = IRB.CreateInsertElement(
ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()),
(uint64_t)0);
IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc)
->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
} else
#endif
{
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc);
}
@ -415,18 +383,67 @@ struct InsTrim : public ModulePass {
}
int has_calls = 0;
for (BasicBlock &BB : F) {
auto PI = pred_begin(&BB);
auto PE = pred_end(&BB);
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
Value * L = NULL;
unsigned int cur_loc;
// Context sensitive coverage
if (ctx_str && &BB == &F.getEntryBlock()) {
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() < function_minimum_size)
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, genLabel());
StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
} // END of ctx_str
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 (PI == PE) {
if (function_minimum_size < 2 && PI == PE) {
L = ConstantInt::get(Int32Ty, genLabel());
cur_loc = genLabel();
L = ConstantInt::get(Int32Ty, cur_loc);
} else {
@ -437,6 +454,7 @@ struct InsTrim : public ModulePass {
BasicBlock *PBB = *PI;
auto It = PredMap.insert({PBB, genLabel()});
unsigned Label = It.first->second;
cur_loc = Label;
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
}
@ -446,15 +464,37 @@ struct InsTrim : public ModulePass {
}
/* Load prev_loc */
LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
Value *PrevLocTrans;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
/* "For efficiency, we propose to hash the tuple as a key into the
hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where
prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
if (ngram_size)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
else
#endif
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
if (ctx_str)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr);
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx =
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, L));
Value *MapPtrIdx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
MapPtrIdx = IRB.CreateGEP(
MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty));
else
#endif
MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L));
/* Update bitmap */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
@ -467,8 +507,7 @@ struct InsTrim : public ModulePass {
NULL) // with llvm 9 we make this the default as the bug in llvm is
// then fixed
#else
if (1) // with llvm 9 we make this the default as the bug in llvm is
// then fixed
if (!skip_nozero)
#endif
{
@ -491,12 +530,20 @@ struct InsTrim : public ModulePass {
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// save the actually location ID to OldPrev if function_minimum_size > 1
if (function_minimum_size > 1) {
if (ctx_str && has_calls) {
Value *Shr = IRB.CreateLShr(L, One32);
IRB.CreateStore(Shr, OldPrev)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// in CTX mode we have to restore the original context for the
// caller - she might be calling other functions which need the
// correct CTX
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}

View File

@ -15,9 +15,9 @@ typedef long double max_align_t;
#include "llvm/IR/BasicBlock.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/CFG.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/Support/CFG.h"
#include "llvm/Support/CFG.h"
#endif
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"

View File

@ -1,88 +0,0 @@
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
}
}
}

View File

@ -2,31 +2,39 @@
## TLDR;
1. This compile mode is very frickle if it works it is amazing, if it fails
- well use afl-clang-fast
This version requires a current llvm 11 compiled from the github master.
2. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
1. 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
1a. Set AFL_LLVM_INSTRUMENT=CFG if you want the InsTrimLTO version
(recommended)
3. You can use it together with llvm_mode: laf-intel and whitelisting
2. 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)
3. It only works with llvm 11 (current github master state)
4. AUTODICTIONARY feature! see below
5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib` also
note that if that target uses _init functions or early constructors then
also set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise
## 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
set during compilation are random - and hence naturally the larger the number
of instrumented locations, the higher the number of edge collisions are in the
map. This can result in not discovering new paths and therefore degrade the
efficiency of the fuzzing.
efficiency of the fuzzing process.
*This issue is understimated in the fuzzing community!*
*This issue is underestimated 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
To reach a solution that prevents any collisions took several approaches
and many dead ends until we got to this:
* We instrument at link time when we have all files pre-compiled
@ -34,49 +42,79 @@ and many dead ends until we got to this:
* 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
* The LLVM 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
* 10-25% 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
afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO
afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
AUTODICTIONARY: 11 strings found
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
```
## Building llvm 11
```
$ sudo apt install binutils-dev # this is *essential*!
$ git clone https://github.com/llvm/llvm-project
$ cd llvm-project
$ mkdir build
$ cd build
$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/
$ make -j $(nproc)
$ export PATH=`pwd`/bin:$PATH
$ export LLVM_CONFIG=`pwd`/bin/llvm-config
$ cd /path/to/AFLplusplus/
$ make
$ cd llvm_mode
$ make
$ cd ..
$ make install
```
## How to use afl-clang-lto
Just use afl-clang-lto like you did afl-clang-fast or afl-gcc.
Just use afl-clang-lto like you did with 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.
InsTrim (control flow graph instrumentation) is supported and recommended!
(set `AFL_LLVM_INSTRUMENT=CFG`)
Example:
```
CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
export AFL_LLVM_INSTRUMENT=CFG
make
```
## AUTODICTIONARY feature
Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
target binary based on string compare and memory compare functions.
afl-fuzz will automatically get these transmitted when starting to fuzz.
This improves coverage on a lot of targets.
## Fixed memory map
To speed up fuzzing, the shared memory map is hard set to a specific address,
by default 0x10000. In most cases this will work without any problems.
On unusual operating systems/processors/kernels or weird libraries this might
fail so to change the fixed address at compile time set
AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address
to be dynamic - the original afl way, which is slower).
AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which
is safer but also slower).
## Potential issues
### compiling libraries fails
@ -92,147 +130,40 @@ 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 ...
and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it.
Other targets ignore environment variables and need the parameters set via
`./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!).
### 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
* Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously
* Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
Hence if building a target with afl-clang-lto fails try to build it with llvm11
and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
`CXXFLAGS=-flto=full`).
An example that does not build with llvm 11 and LTO is ffmpeg.
If this succeeeds then there is an issue with afl-clang-lto. Please report at
[https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
### Target crashes immediately
If the target is using early constructors (priority values smaller than 6)
or have their own _init/.init functions and these are instrumented then the
target will likely crash when started. This can be avoided by compiling with
`AFL_LLVM_MAP_DYNAMIC=1` .
This can e.g. happen with OpenSSL.
## 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
1. Currently the LTO whitelist feature does not allow to instrument main,
start and init functions
## History
@ -249,14 +180,20 @@ 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.
dependencies. At lot of strategies 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 ...
This is all now fixed with llvm 11. The llvm's own linker is now able to
load passes and this bypasses all problems we had.
Happy end :)

View File

@ -37,7 +37,26 @@ co-exists with the original code.
The idea and much of the implementation comes from Laszlo Szekeres.
## 2) How to use this
## 2a) How to use this - short
Set the `LLVM_CONFIG` variable to the clang version you want to use, e.g.
```
LLVM_CONFIG=llvm-config-9 make
```
In case you have your own compiled llvm version specify the full path:
```
LLVM_CONFIG=~/llvm-project/build/bin/llvm-config make
```
If you try to use a new llvm version on an old Linux this can fail because of
old c++ libraries. In this case usually switching to gcc/g++ to compile
llvm_mode will work:
```
LLVM_CONFIG=llvm-config-7 REAL_CC=gcc REAL_CXX=g++ make
```
It is highly recommended to use the newest clang version you can put your
hands on :)
## 2b) How to use this - long
In order to leverage this mechanism, you need to have clang installed on your
system. You should also make sure that the llvm-config tool is in your path

View File

@ -20,8 +20,16 @@ This is implemented in afl-gcc, however for llvm_mode this is optional if
the llvm version is below 9 - as there is a perfomance bug that is only fixed
in version 9 and onwards.
If you want to enable this for llvm < 9 then set
If you want to enable this for llvm versions below 9 then set
```
export AFL_LLVM_NOT_ZERO=1
```
In case you are on llvm 9 or greater and you do not want this behaviour then
you can set:
```
AFL_LLVM_SKIP_NEVERZERO=1
```
If the target does not have extensive loops or functions that are called
a lot then this can give a small performance boost.

View File

@ -43,13 +43,13 @@ 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 */
static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode, cpp_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 {
@ -60,14 +60,15 @@ enum {
INSTRUMENT_INSTRIM = 2,
INSTRUMENT_CFG = 2,
INSTRUMENT_LTO = 3,
INSTRUMENT_CTX = 4,
INSTRUMENT_NGRAM = 5 // + ngram value of 2-16 = 7 - 21
INSTRUMENT_OPT_CTX = 4,
INSTRUMENT_OPT_NGRAM = 8
};
char instrument_mode_string[6][16] = {
char instrument_mode_string[10][16] = {
"DEFAULT", "PCGUARD", "CFG", "LTO", "CTX",
"CLASSIC", "PCGUARD", "CFG", "LTO", "CTX", "",
"", "", "NGRAM", ""
};
@ -159,7 +160,6 @@ static void find_obj(u8 *argv0) {
static void edit_params(u32 argc, char **argv, char **envp) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
u8 has_llvm_config = 0;
u8 *name;
cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
@ -170,9 +170,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
else
++name;
has_llvm_config = (strlen(LLVM_BINDIR) > 0);
if (instrument_mode == INSTRUMENT_LTO)
if (lto_mode)
if (lto_flag[0] != '-')
FATAL(
"Using afl-clang-lto is not possible because Makefile magic did not "
@ -181,29 +179,45 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) {
u8 *alt_cxx = getenv("AFL_CXX");
if (has_llvm_config)
if (USE_BINDIR)
snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", LLVM_BINDIR);
else
sprintf(llvm_fullpath, "clang++");
cc_params[0] = alt_cxx ? alt_cxx : (u8 *)llvm_fullpath;
sprintf(llvm_fullpath, CLANGPP_BIN);
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath;
cpp_mode = 1;
} else if (!strcmp(name, "afl-clang-fast") ||
!strcmp(name, "afl-clang-lto")) {
u8 *alt_cc = getenv("AFL_CC");
if (USE_BINDIR)
snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR);
else
sprintf(llvm_fullpath, CLANG_BIN);
cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath;
} else {
u8 *alt_cc = getenv("AFL_CC");
if (has_llvm_config)
snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR);
else
sprintf(llvm_fullpath, "clang");
cc_params[0] = alt_cc ? alt_cc : (u8 *)llvm_fullpath;
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
FATAL(
"Name of the binary is not a known name, expected afl-clang-fast(++) "
"or afl-clang-lto(++)");
}
/* There are three ways to compile with afl-clang-fast. In the traditional
if (lto_mode && cpp_mode)
cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early
/* There are several ways to compile with afl-clang-fast. In the traditional
mode, we use afl-llvm-pass.so, then there is libLLVMInsTrim.so which is
much faster but has less coverage. Finally there is the experimental
'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
instead. For trace-pc-guard see:
faster and creates less map pollution.
Then there is the 'trace-pc-guard' mode, we use native LLVM
instrumentation callbacks instead. For trace-pc-guard see:
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
The best instrumentatation is with the LTO modes, the classic and
InsTrimLTO, the latter is faster. The LTO modes are activated by using
afl-clang-lto(++)
*/
// laf
@ -220,6 +234,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && lto_mode)
WARNF(
"using AFL_LLVM_LAF_TRANSFORM_COMPARES together with "
"AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only "
"AFL_LLVM_LTO_AUTODICTIONARY.");
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
@ -267,13 +287,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
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 (lto_mode) {
if (getenv("AFL_LLVM_WHITELIST") != NULL) {
@ -285,13 +299,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
#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++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
if (instrument_mode == INSTRUMENT_CFG)
cc_params[cc_par_cnt++] =
alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path);
else
cc_params[cc_par_cnt++] = alloc_printf(
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
cc_params[cc_par_cnt++] = lto_flag;
} else {
@ -318,6 +333,22 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = "-Qunused-arguments";
// in case LLVM is installed not via a package manager or "make install"
// e.g. compiled download or compiled from github then it's ./lib directory
// might not be in the search path. Add it if so.
u8 *libdir = strdup(LLVM_LIBDIR);
if (cpp_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
strncmp(libdir, "/lib", 4)) {
cc_params[cc_par_cnt++] = "-rpath";
cc_params[cc_par_cnt++] = libdir;
} else {
free(libdir);
}
/* Detect stray -v calls from ./configure scripts. */
while (--argc) {
@ -386,7 +417,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("AFL_USE_CFISAN")) {
if (instrument_mode != INSTRUMENT_LTO) {
if (!lto_mode) {
uint32_t i = 0, found = 0;
while (envp[i] != NULL && !found)
@ -410,7 +441,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
if (getenv("AFL_NO_BUILTIN")) {
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
getenv("LAF_TRANSFORM_COMPARES") ||
(lto_mode && (getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
getenv("AFL_LLVM_AUTODICTIONARY")))) {
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
@ -491,21 +525,38 @@ static void edit_params(u32 argc, char **argv, char **envp) {
case 0:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
if (lto_mode)
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
break;
case 32:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
if (lto_mode) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
}
break;
case 64:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
if (lto_mode) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
}
break;
@ -522,7 +573,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
int main(int argc, char **argv, char **envp) {
int i;
char *callname = "afl-clang-fast", *ptr;
char *callname = "afl-clang-fast", *ptr = NULL;
if (getenv("AFL_DEBUG")) {
@ -537,50 +588,6 @@ int main(int argc, char **argv, char **envp) {
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")) {
@ -602,66 +609,180 @@ int main(int argc, char **argv, char **envp) {
}
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_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
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)
instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
FATAL(
"you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_NGRAM_SIZE "
"together");
"NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
"(%u)",
NGRAM_SIZE_MAX);
}
if (instrument_mode < INSTRUMENT_NGRAM)
ptr = instrument_mode_string[instrument_mode];
else
ptr = alloc_printf("NGRAM-%u", instrument_mode - INSTRUMENT_NGRAM);
if (getenv("AFL_LLVM_INSTRUMENT")) {
if (strstr(argv[0], "afl-clang-lto") != NULL) {
u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO) {
while (ptr) {
callname = "afl-clang-lto";
instrument_mode = INSTRUMENT_LTO;
ptr = instrument_mode_string[instrument_mode];
if (strncasecmp(ptr, "default", strlen("default")) == 0 ||
strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
strncasecmp(ptr, "classic", strlen("classic")) == 0) {
} else {
if (!instrument_mode || instrument_mode == INSTRUMENT_DEFAULT)
instrument_mode = INSTRUMENT_DEFAULT;
else
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
if (!be_quiet)
WARNF("afl-clang-lto called with mode %s, using that mode instead",
ptr);
}
if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) {
if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
instrument_mode = INSTRUMENT_PCGUARD;
else
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
}
if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
strncasecmp(ptr, "instrim", strlen("instrim")) == 0) {
if (instrument_mode == INSTRUMENT_LTO) {
instrument_mode = INSTRUMENT_CFG;
lto_mode = 1;
} else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG)
instrument_mode = INSTRUMENT_CFG;
else
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
}
if (strncasecmp(ptr, "lto", strlen("lto")) == 0) {
lto_mode = 1;
if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
instrument_mode = INSTRUMENT_LTO;
else if (instrument_mode != INSTRUMENT_CFG)
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
}
if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) {
instrument_opt_mode |= INSTRUMENT_OPT_CTX;
setenv("AFL_LLVM_CTX", "1", 1);
}
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");
ngram_size = atoi(ptr);
if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
FATAL(
"NGRAM instrumentation option must be between 2 and "
"NGRAM_SIZE_MAX "
"(%u)",
NGRAM_SIZE_MAX);
instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
ptr = alloc_printf("%u", ngram_size);
setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1);
}
ptr = strtok(NULL, ":,;");
}
}
if (strstr(argv[0], "afl-clang-lto") != NULL) {
if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO ||
instrument_mode == INSTRUMENT_CFG) {
lto_mode = 1;
callname = "afl-clang-lto";
if (!instrument_mode) {
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",
instrument_mode_string[instrument_mode]);
}
}
if (instrument_opt_mode && lto_mode)
FATAL(
"CTX and NGRAM can not be used in LTO mode (and would make LTO "
"useless)");
if (!instrument_opt_mode) {
if (lto_mode && instrument_mode == INSTRUMENT_CFG)
ptr = alloc_printf("InsTrimLTO");
else
ptr = instrument_mode_string[instrument_mode];
} else if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]);
else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM)
ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode],
ngram_size);
else
ptr = alloc_printf("%s + CTX + NGRAM-%u",
instrument_mode_string[instrument_mode], ngram_size);
#ifndef AFL_CLANG_FLTO
if (instrument_mode == INSTRUMENT_LTO)
FATAL("instrumentation mode LTO specified but LLVM support not available");
if (lto_mode)
FATAL(
"instrumentation mode LTO specified but LLVM support not available "
"(requires LLVM 11 or higher)");
#endif
if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC &&
instrument_mode != INSTRUMENT_CFG)
FATAL(
"CTX and NGRAM instrumentation options can only be used with CFG "
"(recommended) and CLASSIC instrumentation modes!");
if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
FATAL(
"AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
"together");
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
if (instrument_mode != INSTRUMENT_LTO)
if (!lto_mode)
printf("afl-clang-fast" VERSION " by <lszekeres@google.com> in %s mode\n",
ptr);
else
@ -692,55 +813,54 @@ int main(int argc, char **argv, char **envp) {
"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_DONT_OPTIMIZE: disable optimization instead of -O3\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_INST_RATIO: percentage of branches to instrument\n"
"AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
"AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\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",
"AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
" to cascaded comparisons\n"
"AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
"function calls\n"
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
"AFL_LLVM_WHITELIST: enable whitelisting (selective "
"instrumentation)\n"
"AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
"AFL_PATH: path to instrumenting pass and runtime "
"(afl-llvm-rt.*o)\n"
"AFL_QUIET: suppress verbose output\n"
"AFL_USE_ASAN: activate address sanitizer\n"
"AFL_USE_CFISAN: activate control flow sanitizer\n"
"AFL_USE_MSAN: activate memory sanitizer\n"
"AFL_USE_UBSAN: activate undefined behaviour sanitizer\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");
"(INSTRIM), PCGUARD, LTO, CTX, NGRAM-2 ... NGRAM-16\n"
" You can also use the old environment variables instead:"
" AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
" AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
" AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub "
"option to INSTRIM)\n"
" AFL_LLVM_CTX: use context sensitive coverage\n"
" AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\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"
"AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
"bb\n"
"AFL_REAL_LD: use this lld linker instead of the compiled in path\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",
@ -760,7 +880,7 @@ int main(int argc, char **argv, char **envp) {
getenv("AFL_DEBUG") != NULL) {
if (instrument_mode != INSTRUMENT_LTO)
if (!lto_mode)
SAYF(cCYA "afl-clang-fast" VERSION cRST
" by <lszekeres@google.com> in %s mode\n",
@ -774,6 +894,16 @@ int main(int argc, char **argv, char **envp) {
}
u8 *ptr2;
if (!be_quiet && !lto_mode &&
((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) {
u32 map_size = atoi(ptr2);
if (map_size != MAP_SIZE)
FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast");
}
if (debug) {
SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());

View File

@ -1,839 +0,0 @@
/*
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,242 @@
#define AFL_LLVM_PASS
#include "config.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <list>
#include <string>
#include <fstream>
#include <llvm/Support/raw_ostream.h>
#include "afl-llvm-common.h"
using namespace llvm;
static std::list<std::string> myWhitelist;
char *getBBName(const llvm::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);
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
BB->printAsOperand(OS, false);
#endif
name = strdup(OS.str().c_str());
return name;
}
/* Function that we never instrument or analyze */
/* Note: this blacklist check is also called in isInWhitelist() */
bool isBlacklisted(const llvm::Function *F) {
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based
// fuzzing campaign installations, e.g. oss-fuzz
static const char *Blacklist[] = {
"asan.",
"llvm.",
"sancov.",
"__ubsan_handle_",
"ign.",
"__afl_",
"_fini",
"__libc_csu",
"__asan",
"__msan",
"msan.",
"LLVMFuzzer",
"maybe_duplicate_stderr",
"discard_output",
"close_stdout",
"dup_and_close_stderr",
"maybe_close_fd_mask",
"ExecuteFilesOnyByOne"
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
}
void initWhitelist() {
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 isInWhitelist(llvm::Function *F) {
// is this a function with code? If it is external we dont instrument it
// anyway and cant be in the whitelist. Or if it is blacklisted.
if (!F->size() || isBlacklisted(F)) return false;
// if we do not have a whitelist return true
if (myWhitelist.empty()) return true;
// let's try to get the filename for the function
auto bb = &F->getEntryBlock();
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
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) {
return true;
}
}
}
}
}
#else
if (!Loc.isUnknown()) {
DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
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) {
return true;
}
}
}
}
}
#endif
else {
// we could not find out the location. in this case we say it is not
// in the whitelist
return false;
}
//
return false;
}
// 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;
}

View File

@ -0,0 +1,42 @@
#ifndef __AFLLLVMCOMMON_H
#define __AFLLLVMCOMMON_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/Support/MathExtras.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#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
char * getBBName(const llvm::BasicBlock *BB);
bool isBlacklisted(const llvm::Function *F);
void initWhitelist();
bool isInWhitelist(llvm::Function *F);
unsigned long long int calculateCollisions(uint32_t edges);
#endif

View File

@ -0,0 +1,935 @@
/*
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
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
or afl-clang-lto with AFL_LLVM_INSTRUMENT=CFG or =INSTRIM
*/
#define AFL_LLVM_PASS
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <unordered_set>
#include <list>
#include <string>
#include <fstream>
#include <set>
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/ValueTracking.h"
#include "MarkNodes.h"
#include "afl-llvm-common.h"
#include "config.h"
#include "debug.h"
using namespace llvm;
static cl::opt<bool> MarkSetOpt("markset", cl::desc("MarkSet"),
cl::init(false));
static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
cl::init(false));
namespace {
struct InsTrimLTO : public ModulePass {
protected:
uint32_t function_minimum_size = 1;
char * skip_nozero = NULL;
int afl_global_id = 1, debug = 0, autodictionary = 0;
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0;
uint64_t map_addr = 0x10000;
public:
static char ID;
InsTrimLTO() : 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);
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
ModulePass::getAnalysisUsage(AU);
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
}
StringRef getPassName() const override {
return "InstTrim LTO Instrumentation";
}
bool runOnModule(Module &M) override {
char be_quiet = 0;
char *ptr;
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "InsTrimLTO" VERSION cRST
" by csienslab and Marc \"vanHauser\" Heuse\n");
} else
be_quiet = 1;
/* Process environment variables */
if (getenv("AFL_LLVM_AUTODICTIONARY") ||
getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
autodictionary = 1;
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
uint64_t val;
if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
map_addr = 0;
} else if (map_addr == 0) {
FATAL(
"AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used "
"together");
} else if (strncmp(ptr, "0x", 2) != 0) {
map_addr = 0x10000; // the default
} else {
val = strtoull(ptr, NULL, 16);
if (val < 0x100 || val > 0xffffffff00000000) {
FATAL(
"AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
"0xffffffff00000000");
}
map_addr = val;
}
}
if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); }
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
getenv("LOOPHEAD") != NULL) {
LoopHeadOpt = true;
}
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
// this is our default
MarkSetOpt = true;
/* Initialize LLVM instrumentation */
LLVMContext & C = M.getContext();
std::vector<std::string> dictionary;
std::vector<CallInst *> calls;
DenseMap<Value *, std::string *> valueMap;
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
/* Get/set globals for the SHM region. */
GlobalVariable *AFLMapPtr = NULL;
Value * MapPtrFixed = NULL;
if (!map_addr) {
AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
} else {
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
MapPtrFixed =
ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Ty));
}
if (autodictionary) {
/* Some implementation notes.
*
* We try to handle 3 cases:
* - memcmp("foo", arg, 3) <- literal string
* - static char globalvar[] = "foo";
* memcmp(globalvar, arg, 3) <- global variable
* - char localvar[] = "foo";
* memcmp(locallvar, arg, 3) <- local variable
*
* The local variable case is the hardest. We can only detect that
* case if there is no reassignment or change in the variable.
* And it might not work across llvm version.
* What we do is hooking the initializer function for local variables
* (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
* variable. And if that variable is then used in a compare function
* we use that noted string.
* This seems not to work for tokens that have a size <= 4 :-(
*
* - if the compared length is smaller than the string length we
* save the full string. This is likely better for fuzzing but
* might be wrong in a few cases depending on optimizers
*
* - not using StringRef because there is a bug in the llvm 11
* checkout I am using which sometimes points to wrong strings
*
* Over and out. Took me a full day. damn. mh/vh
*/
for (Function &F : M) {
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
bool isStrcmp = true;
bool isMemcmp = true;
bool isStrncmp = true;
bool isStrcasecmp = true;
bool isStrncasecmp = true;
bool isIntMemcpy = true;
bool addedNull = false;
uint8_t optLen = 0;
Function *Callee = callInst->getCalledFunction();
if (!Callee) continue;
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
std::string FuncName = Callee->getName().str();
isStrcmp &= !FuncName.compare("strcmp");
isMemcmp &= !FuncName.compare("memcmp");
isStrncmp &= !FuncName.compare("strncmp");
isStrcasecmp &= !FuncName.compare("strcasecmp");
isStrncasecmp &= !FuncName.compare("strncasecmp");
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp
* function prototype */
FunctionType *FT = Callee->getFunctionType();
isStrcmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isStrcasecmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isMemcmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0)->isPointerTy() &&
FT->getParamType(1)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy();
isStrncmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
isStrncasecmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* is a str{n,}{case,}cmp/memcmp, check if we have
* str{case,}cmp(x, "const") or str{case,}cmp("const", x)
* strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x,
* ..) memcmp(x, "const", ..) or memcmp("const", x, ..) */
Value *Str1P = callInst->getArgOperand(0),
*Str2P = callInst->getArgOperand(1);
std::string Str1, Str2;
StringRef TmpStr;
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty())
HasStr1 = false;
else
Str1 = TmpStr.str();
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
if (TmpStr.empty())
HasStr2 = false;
else
Str2 = TmpStr.str();
if (debug)
fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
Str2P->getName().str().c_str(), Str2.c_str(),
HasStr2 == true ? "true" : "false");
// we handle the 2nd parameter first because of llvm memcpy
if (!HasStr2) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var =
dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
}
}
}
}
}
// for the internal memcpy routine we only care for the second
// parameter and are not reporting anything.
if (isIntMemcpy == true) {
if (HasStr2 == true) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = Str2.size();
uint64_t optLength = ilen->getZExtValue();
if (literalLength + 1 == optLength) {
Str2.append("\0", 1); // add null byte
addedNull = true;
}
}
valueMap[Str1P] = new std::string(Str2);
if (debug)
fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
continue;
}
continue;
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr2) {
std::string *strng = valueMap[Str2P];
if (strng && !strng->empty()) {
Str2 = *strng;
HasStr2 = true;
if (debug)
fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
Str2P);
}
}
if (!HasStr1) {
auto Ptr = dyn_cast<ConstantExpr>(Str1P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var =
dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
}
}
}
}
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr1) {
std::string *strng = valueMap[Str1P];
if (strng && !strng->empty()) {
Str1 = *strng;
HasStr1 = true;
if (debug)
fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
Str1P);
}
}
/* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) continue;
std::string thestring;
if (HasStr1)
thestring = Str1;
else
thestring = Str2;
optLen = thestring.length();
if (isMemcmp || isStrncmp || isStrncasecmp) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = optLen;
optLen = ilen->getZExtValue();
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
}
}
}
// add null byte if this is a string compare function and a null
// was not already added
if (addedNull == false && !isMemcmp) {
thestring.append("\0", 1); // add null byte
optLen++;
}
if (!be_quiet) {
std::string outstring;
fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
(unsigned int)thestring.length());
for (uint8_t i = 0; i < thestring.length(); i++) {
uint8_t c = thestring[i];
if (c <= 32 || c >= 127)
fprintf(stderr, "\\x%02x", c);
else
fprintf(stderr, "%c", c);
}
fprintf(stderr, "\"\n");
}
// we take the longer string, even if the compare was to a
// shorter part. Note that depending on the optimizer of the
// compiler this can be wrong, but it is more likely that this
// is helping the fuzzer
if (optLen != thestring.length()) optLen = thestring.length();
if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
if (optLen < MIN_AUTO_EXTRA) // too short? skip
continue;
dictionary.push_back(thestring.substr(0, optLen));
}
}
}
}
}
/* InsTrim instrumentation starts here */
u64 total_rs = 0;
u64 total_hs = 0;
for (Function &F : M) {
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 (isBlacklisted(&F)) continue;
std::unordered_set<BasicBlock *> MS;
if (!MarkSetOpt) {
for (auto &BB : F) {
MS.insert(&BB);
}
total_rs += F.size();
} else {
auto Result = markNodes(&F);
auto RS = Result.first;
auto HS = Result.second;
MS.insert(RS.begin(), RS.end());
if (!LoopHeadOpt) {
MS.insert(HS.begin(), HS.end());
total_rs += MS.size();
} else {
DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
DominatorTreeWrapperPass * DTWP =
&getAnalysis<DominatorTreeWrapperPass>(F);
auto DT = &DTWP->getDomTree();
total_rs += RS.size();
total_hs += HS.size();
for (BasicBlock *BB : HS) {
bool Inserted = false;
for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {
auto Edge = BasicBlockEdge(*BI, BB);
if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
EdgeSet.insert({*BI, BB});
Inserted = true;
break;
}
}
if (!Inserted) {
MS.insert(BB);
total_rs += 1;
total_hs -= 1;
}
}
for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
auto PredBB = I->first;
auto SuccBB = I->second;
auto NewBB = SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT,
nullptr, nullptr, false);
MS.insert(NewBB);
}
}
}
for (BasicBlock &BB : F) {
auto PI = pred_begin(&BB);
auto PE = pred_end(&BB);
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
Value * L = NULL;
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
if (PI == PE) {
L = ConstantInt::get(Int32Ty, afl_global_id++);
} else {
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
DenseMap<BasicBlock *, unsigned> PredMap;
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
BasicBlock *PBB = *PI;
auto It = PredMap.insert({PBB, afl_global_id++});
unsigned Label = It.first->second;
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
}
L = PN;
}
/* Load SHM pointer */
Value *MapPtrIdx;
if (map_addr) {
MapPtrIdx = IRB.CreateGEP(MapPtrFixed, L);
} else {
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
MapPtrIdx = IRB.CreateGEP(MapPtr, L);
}
/* Update bitmap */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *Incr = IRB.CreateAdd(Counter, One);
if (skip_nozero) {
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
}
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// done :)
inst_blocks++;
}
}
// save highest location ID to global variable
// do this after each function to fail faster
if (!be_quiet && afl_global_id > MAP_SIZE &&
afl_global_id > FS_OPT_MAX_MAPSIZE) {
uint32_t pow2map = 1, map = afl_global_id;
while ((map = map >> 1))
pow2map++;
WARNF(
"We have %u blocks to instrument but the map size is only %u. Either "
"edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
"afl-fuzz and llvm_mode and then make this target - or set "
"AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
"target.",
afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id);
}
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
Function *f = M.getFunction("__afl_auto_init_globals");
if (!f) {
fprintf(stderr,
"Error: init function could not be found (this should not "
"happen)\n");
exit(-1);
}
BasicBlock *bb = &f->getEntryBlock();
if (!bb) {
fprintf(stderr,
"Error: init function does not have an EntryBlock (this should "
"not happen)\n");
exit(-1);
}
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (map_addr) {
GlobalVariable *AFLMapAddrFixed =
new GlobalVariable(M, Int64Ty, true, GlobalValue::ExternalLinkage,
0, "__afl_map_addr");
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
uint32_t write_loc = afl_global_id;
if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
GlobalVariable *AFLFinalLoc =
new GlobalVariable(M, Int32Ty, true, GlobalValue::ExternalLinkage,
0, "__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (dictionary.size()) {
size_t memlen = 0, count = 0, offset = 0;
char * ptr;
for (auto token : dictionary) {
memlen += token.length();
count++;
}
if (!be_quiet)
printf("AUTODICTIONARY: %lu string%s found\n", count,
count == 1 ? "" : "s");
if (count) {
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
memlen + count);
exit(-1);
}
count = 0;
for (auto token : dictionary) {
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
ptr[offset++] = (uint8_t)token.length();
memcpy(ptr + offset, token.c_str(), token.length());
offset += token.length();
count++;
}
}
GlobalVariable *AFLDictionaryLen = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
"__afl_dictionary_len");
ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
StoreInst * StoreDictLen =
IRB.CreateStore(const_len, AFLDictionaryLen);
StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
GlobalVariable *AFLInternalDictionary = new GlobalVariable(
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))),
"__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))));
AFLInternalDictionary->setConstant(true);
GlobalVariable *AFLDictionary = new GlobalVariable(
M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
Value *AFLDictPtr =
IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
StoreDict->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
}
// count basic blocks for comparison with classic instrumentation
u32 edges = 0;
for (auto &F : M) {
if (F.size() < function_minimum_size) continue;
for (auto &BB : F) {
bool would_instrument = false;
for (BasicBlock *Pred : predecessors(&BB)) {
int count = 0;
for (BasicBlock *Succ : successors(Pred))
if (Succ != NULL) count++;
if (count > 1) return true;
}
if (would_instrument == true) edges++;
}
}
/* 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 (%llu, %llu) with no collisions (on "
"average %llu collisions would be in afl-gcc/afl-clang-fast for %u "
"edges) (%s mode).",
inst_blocks, total_rs, total_hs, calculateCollisions(edges), edges,
modeline);
}
}
return true;
}
}; // end of struct InsTrim
} // end of anonymous namespace
char InsTrimLTO::ID = 0;
static void registerInsTrimLTO(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new InsTrimLTO());
}
static RegisterPass<InsTrimLTO> X("afl-lto-instrim",
"afl++ InsTrim LTO instrumentation pass",
false, false);
static RegisterStandardPasses RegisterInsTrimLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerInsTrimLTO);

View File

@ -1,14 +1,9 @@
/*
american fuzzy lop++ - LLVM-mode instrumentation pass
---------------------------------------------------
american fuzzy lop++ - LLVM LTO instrumentation pass
----------------------------------------------------
Written by Laszlo Szekeres <lszekeres@google.com> and
Michal Zalewski
Written by Marc Heuse <mh@mh-sec.de>
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");
@ -17,18 +12,10 @@
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.
This library is plugged into LLVM when invoking clang through afl-clang-lto.
*/
// 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"
@ -37,38 +24,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <list>
#include <string>
#include <fstream>
#include <sys/time.h>
#include <set>
#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
typedef long double max_align_t;
#endif
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.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
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Pass.h"
#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
#include "afl-llvm-common.h"
using namespace llvm;
@ -89,9 +71,10 @@ class AFLLTOPass : public ModulePass {
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n",
ptr, MAP_SIZE - 1);
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
}
#ifdef USE_SPLIT
void getAnalysisUsage(AnalysisUsage &AU) const override {
ModulePass::getAnalysisUsage(AU);
@ -100,76 +83,14 @@ class AFLLTOPass : public ModulePass {
}
#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;
int afl_global_id = 1, debug = 0, autodictionary = 0;
uint32_t function_minimum_size = 1;
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
uint64_t map_addr = 0x10000;
char * skip_nozero = NULL;
};
@ -177,22 +98,19 @@ class AFLLTOPass : public ModulePass {
bool AFLLTOPass::runOnModule(Module &M) {
LLVMContext &C = M.getContext();
LLVMContext & C = M.getContext();
std::vector<std::string> dictionary;
std::vector<CallInst *> calls;
DenseMap<Value *, std::string *> valueMap;
char * ptr;
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);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
/* Show a banner */
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
SAYF(cCYA "afl-llvm-lto" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
@ -201,16 +119,69 @@ bool AFLLTOPass::runOnModule(Module &M) {
be_quiet = 1;
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#endif
if (getenv("AFL_LLVM_AUTODICTIONARY") ||
getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
autodictionary = 1;
/* Get globals for the SHM region and the previous location. Note that
__afl_prev_loc is thread-local. */
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
GlobalVariable *AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
uint64_t val;
if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
map_addr = 0;
} else if (map_addr == 0) {
FATAL(
"AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
} else if (strncmp(ptr, "0x", 2) != 0) {
map_addr = 0x10000; // the default
} else {
val = strtoull(ptr, NULL, 16);
if (val < 0x100 || val > 0xffffffff00000000) {
FATAL(
"AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
"0xffffffff00000000");
}
map_addr = val;
}
}
if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); }
/* Get/set the globals for the SHM region. */
GlobalVariable *AFLMapPtr = NULL;
Value * MapPtrFixed = NULL;
if (!map_addr) {
AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
} else {
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
MapPtrFixed =
ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Ty));
}
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
@ -221,17 +192,333 @@ bool AFLLTOPass::runOnModule(Module &M) {
for (auto &F : M) {
if (F.size() < 2) continue;
// fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str());
if (F.size() < function_minimum_size) 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;
if (autodictionary) {
/* Some implementation notes.
*
* We try to handle 3 cases:
* - memcmp("foo", arg, 3) <- literal string
* - static char globalvar[] = "foo";
* memcmp(globalvar, arg, 3) <- global variable
* - char localvar[] = "foo";
* memcmp(locallvar, arg, 3) <- local variable
*
* The local variable case is the hardest. We can only detect that
* case if there is no reassignment or change in the variable.
* And it might not work across llvm version.
* What we do is hooking the initializer function for local variables
* (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
* variable. And if that variable is then used in a compare function
* we use that noted string.
* This seems not to work for tokens that have a size <= 4 :-(
*
* - if the compared length is smaller than the string length we
* save the full string. This is likely better for fuzzing but
* might be wrong in a few cases depending on optimizers
*
* - not using StringRef because there is a bug in the llvm 11
* checkout I am using which sometimes points to wrong strings
*
* Over and out. Took me a full day. damn. mh/vh
*/
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
bool isStrcmp = true;
bool isMemcmp = true;
bool isStrncmp = true;
bool isStrcasecmp = true;
bool isStrncasecmp = true;
bool isIntMemcpy = true;
bool addedNull = false;
uint8_t optLen = 0;
Function *Callee = callInst->getCalledFunction();
if (!Callee) continue;
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
std::string FuncName = Callee->getName().str();
isStrcmp &= !FuncName.compare("strcmp");
isMemcmp &= !FuncName.compare("memcmp");
isStrncmp &= !FuncName.compare("strncmp");
isStrcasecmp &= !FuncName.compare("strcasecmp");
isStrncasecmp &= !FuncName.compare("strncasecmp");
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
* prototype */
FunctionType *FT = Callee->getFunctionType();
isStrcmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isStrcasecmp &= FT->getNumParams() == 2 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext());
isMemcmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0)->isPointerTy() &&
FT->getParamType(1)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy();
isStrncmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
isStrncasecmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp && !isIntMemcpy)
continue;
/* is a str{n,}{case,}cmp/memcmp, check if we have
* str{case,}cmp(x, "const") or str{case,}cmp("const", x)
* strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
* memcmp(x, "const", ..) or memcmp("const", x, ..) */
Value *Str1P = callInst->getArgOperand(0),
*Str2P = callInst->getArgOperand(1);
std::string Str1, Str2;
StringRef TmpStr;
bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty())
HasStr1 = false;
else
Str1 = TmpStr.str();
bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
if (TmpStr.empty())
HasStr2 = false;
else
Str2 = TmpStr.str();
if (debug)
fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
Str2P->getName().str().c_str(), Str2.c_str(),
HasStr2 == true ? "true" : "false");
// we handle the 2nd parameter first because of llvm memcpy
if (!HasStr2) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
}
}
}
}
}
// for the internal memcpy routine we only care for the second
// parameter and are not reporting anything.
if (isIntMemcpy == true) {
if (HasStr2 == true) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = Str2.size();
uint64_t optLength = ilen->getZExtValue();
if (literalLength + 1 == optLength) {
Str2.append("\0", 1); // add null byte
addedNull = true;
}
}
valueMap[Str1P] = new std::string(Str2);
if (debug)
fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
continue;
}
continue;
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr2) {
std::string *strng = valueMap[Str2P];
if (strng && !strng->empty()) {
Str2 = *strng;
HasStr2 = true;
if (debug)
fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
Str2P);
}
}
if (!HasStr1) {
auto Ptr = dyn_cast<ConstantExpr>(Str1P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
}
}
}
}
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr1) {
std::string *strng = valueMap[Str1P];
if (strng && !strng->empty()) {
Str1 = *strng;
HasStr1 = true;
if (debug)
fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
Str1P);
}
}
/* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) continue;
std::string thestring;
if (HasStr1)
thestring = Str1;
else
thestring = Str2;
optLen = thestring.length();
if (isMemcmp || isStrncmp || isStrncasecmp) {
Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = optLen;
optLen = ilen->getZExtValue();
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
}
}
}
// add null byte if this is a string compare function and a null
// was not already added
if (addedNull == false && !isMemcmp) {
thestring.append("\0", 1); // add null byte
optLen++;
}
if (!be_quiet) {
std::string outstring;
fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
(unsigned int)thestring.length());
for (uint8_t i = 0; i < thestring.length(); i++) {
uint8_t c = thestring[i];
if (c <= 32 || c >= 127)
fprintf(stderr, "\\x%02x", c);
else
fprintf(stderr, "%c", c);
}
fprintf(stderr, "\"\n");
}
// we take the longer string, even if the compare was to a
// shorter part. Note that depending on the optimizer of the
// compiler this can be wrong, but it is more likely that this
// is helping the fuzzer
if (optLen != thestring.length()) optLen = thestring.length();
if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
if (optLen < MIN_AUTO_EXTRA) // too short? skip
continue;
dictionary.push_back(thestring.substr(0, optLen));
}
}
}
}
for (auto &BB : F) {
uint32_t succ = 0;
@ -274,11 +561,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
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) {
@ -287,12 +570,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
#ifdef USE_SPLIT
BasicBlock::iterator IP = newBB->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
#else
IRBuilder<> IRB(&(*newBB));
#endif
/* Set the ID of the inserted basic block */
@ -300,10 +579,20 @@ bool AFLLTOPass::runOnModule(Module &M) {
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
Value *MapPtrIdx;
if (map_addr) {
MapPtrIdx = IRB.CreateGEP(MapPtrFixed, CurLoc);
} else {
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc);
}
/* Update bitmap */
@ -313,38 +602,17 @@ bool AFLLTOPass::runOnModule(Module &M) {
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
if (skip_nozero) {
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++;
@ -358,28 +626,151 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
// save highest location ID to global variable
if (afl_global_id > MAP_SIZE) {
// do this after each function to fail faster
if (!be_quiet && afl_global_id > MAP_SIZE &&
afl_global_id > FS_OPT_MAX_MAPSIZE) {
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);
WARNF(
"We have %u blocks to instrument but the map size is only %u. Either "
"edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
"afl-fuzz and llvm_mode and then make this target - or set "
"AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
"target.",
afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id);
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
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);
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
Function *f = M.getFunction("__afl_auto_init_globals");
if (!f) {
fprintf(stderr,
"Error: init function could not be found (this should not "
"happen)\n");
exit(-1);
}
BasicBlock *bb = &f->getEntryBlock();
if (!bb) {
fprintf(stderr,
"Error: init function does not have an EntryBlock (this should "
"not happen)\n");
exit(-1);
}
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (map_addr) {
GlobalVariable *AFLMapAddrFixed = new GlobalVariable(
M, Int64Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr");
ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr);
StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
uint32_t write_loc = afl_global_id;
if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
GlobalVariable *AFLFinalLoc = new GlobalVariable(
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
if (dictionary.size()) {
size_t memlen = 0, count = 0, offset = 0;
char * ptr;
for (auto token : dictionary) {
memlen += token.length();
count++;
}
if (!be_quiet)
printf("AUTODICTIONARY: %lu string%s found\n", count,
count == 1 ? "" : "s");
if (count) {
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
memlen + count);
exit(-1);
}
count = 0;
for (auto token : dictionary) {
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
ptr[offset++] = (uint8_t)token.length();
memcpy(ptr + offset, token.c_str(), token.length());
offset += token.length();
count++;
}
}
GlobalVariable *AFLDictionaryLen =
new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage,
0, "__afl_dictionary_len");
ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
GlobalVariable *AFLInternalDictionary = new GlobalVariable(
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(C,
*(new ArrayRef<char>((char *)ptr, offset))),
"__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))));
AFLInternalDictionary->setConstant(true);
GlobalVariable *AFLDictionary = new GlobalVariable(
M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage,
0, "__afl_dictionary");
Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
Value *AFLDictPtr =
IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
StoreDict->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
}
@ -423,5 +814,5 @@ static RegisterPass<AFLLTOPass> X("afl-lto", "afl++ LTO instrumentation pass",
false, false);
static RegisterStandardPasses RegisterAFLLTOPass(
PassManagerBuilder::EP_OptimizerLast, registerAFLLTOPass);
PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerAFLLTOPass);

View File

@ -46,6 +46,8 @@
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/IR/CFG.h"
#include "afl-llvm-common.h"
using namespace llvm;
namespace {
@ -86,25 +88,6 @@ class AFLwhitelist : public ModulePass {
}
// 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 {
@ -128,7 +111,7 @@ bool AFLwhitelist::runOnModule(Module &M) {
char be_quiet = 0;
if (isatty(2) && !getenv("AFL_QUIET")) {
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-llvm-lto-whitelist" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");

View File

@ -54,13 +54,14 @@ typedef long double max_align_t;
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#endif
#include "afl-llvm-common.h"
#include "llvm-ngram-coverage.h"
using namespace llvm;
@ -73,59 +74,18 @@ class AFLCoverage : public ModulePass {
static char ID;
AFLCoverage() : 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);
}
}
}
// ripped from aflgo
static bool isBlacklisted(const Function *F) {
static const char *Blacklist[] = {
"asan.",
"llvm.",
"sancov.",
"__ubsan_handle_",
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
initWhitelist();
}
bool runOnModule(Module &M) override;
// StringRef getPassName() const override {
// return "American Fuzzy Lop Instrumentation";
// }
protected:
std::list<std::string> myWhitelist;
uint32_t ngram_size = 0;
uint32_t debug = 0;
char * ctx_str = NULL;
uint32_t ngram_size = 0;
uint32_t debug = 0;
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
char * ctx_str = NULL, *skip_nozero = NULL;
};
@ -155,7 +115,7 @@ uint64_t PowerOf2Ceil(unsigned in) {
/* #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
#define AFL_HAVE_VECTOR_INTRINSICS 1
#endif
bool AFLCoverage::runOnModule(Module &M) {
@ -192,6 +152,19 @@ bool AFLCoverage::runOnModule(Module &M) {
be_quiet = 1;
/*
char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
map_size = atoi(ptr);
if (map_size < 8 || map_size > (1 << 29))
FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30",
map_size); if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3);
}
*/
/* Decide instrumentation ratio */
char * inst_ratio_str = getenv("AFL_INST_RATIO");
@ -208,8 +181,13 @@ bool AFLCoverage::runOnModule(Module &M) {
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#endif
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
unsigned PrevLocSize;
if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
getenv("AFL_LLVM_SKIPSINGLEBLOCK"))
function_minimum_size = 2;
unsigned PrevLocSize = 0;
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
@ -233,8 +211,15 @@ bool AFLCoverage::runOnModule(Module &M) {
else
#else
if (ngram_size_str)
FATAL("Sorry, NGRAM branch coverage is not supported with llvm version %s!",
LLVM_VERSION_STRING);
#ifndef LLVM_VERSION_PATCH
FATAL("Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR,
0);
#else
FATAL("Sorry, NGRAM branch coverage is not supported with llvm version %d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR,
LLVM_VERSION_PATCH);
#endif
#endif
PrevLocSize = 1;
@ -243,9 +228,6 @@ bool AFLCoverage::runOnModule(Module &M) {
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. */
@ -267,17 +249,17 @@ bool AFLCoverage::runOnModule(Module &M) {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
#ifdef __ANDROID__
#ifdef __ANDROID__
AFLPrevLoc = new GlobalVariable(
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_loc");
#else
#else
AFLPrevLoc = new GlobalVariable(
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_loc",
/* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
/* AddressSpace */ 0, /* IsExternallyInitialized */ false);
#endif
#endif
else
#endif
#ifdef __ANDROID__
@ -322,116 +304,40 @@ bool AFLCoverage::runOnModule(Module &M) {
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
F.size());
if (isBlacklisted(&F)) continue;
if (!isInWhitelist(&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));
}
}
if (F.size() < function_minimum_size) continue;
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (!myWhitelist.empty()) {
// Context sensitive coverage
if (ctx_str && &BB == &F.getEntryBlock()) {
bool instrumentBlock = false;
// load the context ID of the previous function and write to to a local
// variable on the stack
PrevCtx = IRB.CreateLoad(AFLContext);
PrevCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* 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) {
// does the function have calls? and is any of the calls larger than one
// basic block?
for (auto &BB : F) {
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
if (has_calls) break;
for (auto &IN : BB) {
unsigned int instLine = cDILoc->getLine();
StringRef instFilename = cDILoc->getFilename();
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
if (instFilename.str().empty()) {
Function *Callee = callInst->getCalledFunction();
if (!Callee || Callee->size() < function_minimum_size)
continue;
else {
/* 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;
}
has_calls = 1;
break;
}
@ -441,64 +347,13 @@ bool AFLCoverage::runOnModule(Module &M) {
}
#else
if (!Loc.isUnknown()) {
// if yes we store a context ID for this function in the global var
if (has_calls) {
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;
}
// 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));
ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size));
StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
@ -509,7 +364,7 @@ bool AFLCoverage::runOnModule(Module &M) {
/* Make up cur_loc */
// cur_loc++;
cur_loc = AFL_R(MAP_SIZE);
cur_loc = AFL_R(map_size);
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
The inline function successors() is not inlined and also not found at runtime
@ -548,7 +403,28 @@ bool AFLCoverage::runOnModule(Module &M) {
}
// fprintf(stderr, " == %d\n", more_than_one);
if (more_than_one != 1) continue;
if (F.size() > 1 && more_than_one != 1) {
// 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));
}
}
continue;
}
#endif
ConstantInt *CurLoc;
@ -572,13 +448,17 @@ bool AFLCoverage::runOnModule(Module &M) {
prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */
if (ngram_size)
PrevLocTrans = IRB.CreateXorReduce(PrevLoc);
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty());
else
#endif
if (ctx_str)
PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLoc, PrevCtx), Int32Ty);
PrevLocTrans = PrevLoc;
if (ctx_str)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
else
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
PrevLocTrans = IRB.CreateZExt(PrevLocTrans, IRB.getInt32Ty());
/* Load SHM pointer */
@ -590,7 +470,9 @@ bool AFLCoverage::runOnModule(Module &M) {
if (ngram_size)
MapPtrIdx = IRB.CreateGEP(
MapPtr,
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, CurLoc), Int32Ty));
IRB.CreateZExt(
IRB.CreateXor(PrevLocTrans, IRB.CreateZExt(CurLoc, Int32Ty)),
Int32Ty));
else
#endif
MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
@ -606,6 +488,9 @@ bool AFLCoverage::runOnModule(Module &M) {
if (neverZero_counters_str !=
NULL) { // with llvm 9 we make this the default as the bug in llvm is
// then fixed
#else
if (!skip_nozero) {
#endif
/* hexcoder: Realize a counter that skips zero during overflow.
* Once this counter reaches its maximum value, it next increments to 1
@ -616,60 +501,13 @@ bool AFLCoverage::runOnModule(Module &M) {
* Counter + 1 -> {Counter, OverflowFlag}
* Counter + OverflowFlag -> Counter
*/
/* // we keep the old solutions just in case
// Solution #1
if (neverZero_counters_str[0] == '1') {
CallInst *AddOv =
IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter,
ConstantInt::get(Int8Ty, 1));
AddOv->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None)); Value *SumWithOverflowBit = AddOv; Incr =
IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum
IRB.CreateZExt( // convert from one bit
type to 8 bits type IRB.CreateExtractValue(SumWithOverflowBit, 1), //
overflow Int8Ty));
// Solution #2
} else if (neverZero_counters_str[0] == '2') {
auto cf = IRB.CreateICmpEQ(Counter,
ConstantInt::get(Int8Ty, 255)); Value *HowMuch =
IRB.CreateAdd(ConstantInt::get(Int8Ty, 1), cf); Incr =
IRB.CreateAdd(Counter, HowMuch);
// Solution #3
} else if (neverZero_counters_str[0] == '3') {
*/
// this is the solution we choose because llvm9 should do the right
// thing here
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
/*
// Solution #4
} else if (neverZero_counters_str[0] == '4') {
auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1));
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
} else {
fprintf(stderr, "Error: unknown value for AFL_NZERO_COUNTS: %s
(valid is 1-4)\n", neverZero_counters_str); exit(-1);
}
*/
#if LLVM_VERSION_MAJOR < 9
}
#endif
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
@ -699,12 +537,78 @@ 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.
// Currently this is only needed for the Ubuntu clang-6.0 bug
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));
}
}
inst_blocks++;
}
}
/*
// This is currently disabled because we not only need to create/insert a
// function (easy), but also add it as a constructor with an ID < 5
if (getenv("AFL_LLVM_DONTWRITEID") == NULL) {
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt.o
Function *f = ...
if (!f) {
fprintf(stderr,
"Error: init function could not be created (this should not
happen)\n"); exit(-1);
}
... constructor for f = 4
BasicBlock *bb = &f->getEntryBlock();
if (!bb) {
fprintf(stderr,
"Error: init function does not have an EntryBlock (this should
not happen)\n"); exit(-1);
}
BasicBlock::iterator IP = bb->getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (map_size <= 0x800000) {
GlobalVariable *AFLFinalLoc = new GlobalVariable(
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
"__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
*/
/* Say something nice. */
if (!be_quiet) {

View File

@ -0,0 +1,27 @@
/*
american fuzzy lop++ - LLVM instrumentation bootstrap
-----------------------------------------------------
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>
// to prevent the function from being removed
unsigned char __afl_lto_mode = 0;
/* Proper initialization routine. */
__attribute__((constructor(0))) void __afl_auto_init_globals(void) {
if (getenv("AFL_DEBUG")) fprintf(stderr, "[__afl_auto_init_globals]\n");
__afl_lto_mode = 1;
}

View File

@ -21,7 +21,7 @@
*/
#ifdef __ANDROID__
#include "android-ashmem.h"
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
@ -43,18 +43,18 @@
#include <sys/types.h>
#ifdef __linux__
#include "snapshot-inl.h"
#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. */
#ifdef USE_TRACE_PC
#define CONST_PRIO 5
#else
#define CONST_PRIO 0
#endif /* ^USE_TRACE_PC */
#ifndef MAP_FIXED_NOREPLACE
#define MAP_FIXED_NOREPLACE MAP_FIXED
#endif
#include <sys/mman.h>
#include <fcntl.h>
@ -63,17 +63,25 @@
is used for instrumentation output before __afl_map_shm() has a chance to
run. It will end up as .comm, so it shouldn't be too wasteful. */
u8 __afl_area_initial[MAP_SIZE];
#ifdef AFL_REAL_LD
u8 __afl_area_initial[256000];
#else
u8 __afl_area_initial[MAP_SIZE];
#endif
u8 *__afl_area_ptr = __afl_area_initial;
u8 *__afl_dictionary;
u32 __afl_final_loc;
u32 __afl_map_size = MAP_SIZE;
u32 __afl_dictionary_len;
u64 __afl_map_addr;
#ifdef __ANDROID__
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
u32 __afl_final_loc;
u32 __afl_prev_ctx;
u32 __afl_cmp_counter;
#else
__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
@ -84,16 +92,72 @@ struct cmp_map *__afl_cmp_map;
static u8 is_persistent;
/* Error reporting to forkserver controller */
void send_forkserver_error(int error) {
u32 status;
if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
}
/* SHM setup. */
static void __afl_map_shm(void) {
u8 *id_str = getenv(SHM_ENV_VAR);
char *id_str = getenv(SHM_ENV_VAR);
if (__afl_final_loc) {
__afl_map_size = __afl_final_loc;
if (__afl_final_loc > MAP_SIZE) {
char *ptr;
u32 val = 0;
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) val = atoi(ptr);
if (val < __afl_final_loc) {
if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
fprintf(stderr,
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_final_loc);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
fprintf(stderr,
"Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
"be able to run this instrumented program!\n",
__afl_final_loc);
}
}
}
}
/* If we're running under AFL, attach to the appropriate region, replacing the
early-stage __afl_area_initial region that is needed to allow some really
hacky .init code to work correctly in projects such as OpenSSL. */
if (getenv("AFL_DEBUG"))
fprintf(stderr,
"DEBUG: id_str %s, __afl_map_addr 0x%llx, MAP_SIZE %u, "
"__afl_final_loc %u, max_size_forkserver %u/0x%x\n",
id_str == NULL ? "<null>" : id_str, __afl_map_addr, MAP_SIZE,
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
if (id_str) {
#ifdef USEMMAP
@ -106,18 +170,35 @@ static void __afl_map_shm(void) {
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n");
send_forkserver_error(FS_ERROR_SHM_OPEN);
exit(1);
}
/* map the shared memory segment to the address space of the process */
shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (__afl_map_addr) {
shm_base =
mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
} else {
shm_base = mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
shm_fd, 0);
}
if (shm_base == MAP_FAILED) {
close(shm_fd);
shm_fd = -1;
fprintf(stderr, "mmap() failed\n");
if (__afl_map_addr)
send_forkserver_error(FS_ERROR_MAP_ADDR);
else
send_forkserver_error(FS_ERROR_MMAP);
exit(2);
}
@ -126,18 +207,40 @@ static void __afl_map_shm(void) {
#else
u32 shm_id = atoi(id_str);
__afl_area_ptr = shmat(shm_id, NULL, 0);
__afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0);
#endif
/* Whooooops. */
if (__afl_area_ptr == (void *)-1) _exit(1);
if (__afl_area_ptr == (void *)-1) {
if (__afl_map_addr)
send_forkserver_error(FS_ERROR_MAP_ADDR);
else
send_forkserver_error(FS_ERROR_SHMAT);
_exit(1);
}
/* Write something into the bitmap so that even with low AFL_INST_RATIO,
our parent doesn't give up on us. */
__afl_area_ptr[0] = 1;
} else if (__afl_map_addr) {
__afl_area_ptr =
mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (__afl_area_ptr == MAP_FAILED) {
fprintf(stderr, "can not aquire mmap for address %p\n",
(void *)__afl_map_addr);
exit(1);
}
}
id_str = getenv(CMPLOG_SHM_ENV_VAR);
@ -187,8 +290,11 @@ static void __afl_map_shm(void) {
#ifdef __linux__
static void __afl_start_snapshots(void) {
static u8 tmp[4];
static u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0;
u32 already_read_first = 0;
u32 was_killed;
u8 child_stopped = 0;
@ -197,16 +303,74 @@ static void __afl_start_snapshots(void) {
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT);
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
memcpy(tmp, &status, 4);
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
if (__afl_dictionary_len > 0 && __afl_dictionary) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
(FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
s32 ret;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
}
while (len != 0) {
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver master does not understand extended option passing
// or does not want the dictionary
already_read_first = 1;
}
}
while (1) {
u32 was_killed;
int status;
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (already_read_first) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
already_read_first = 0;
} else {
/* 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
@ -291,26 +455,88 @@ static void __afl_start_forkserver(void) {
#endif
static u8 tmp[4];
s32 child_pid;
u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0;
u32 already_read_first = 0;
u32 was_killed;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
if (status) status |= (FS_OPT_ENABLED);
memcpy(tmp, &status, 4);
/* 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;
if (__afl_dictionary_len > 0 && __afl_dictionary) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
(FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
s32 ret;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
}
while (len != 0) {
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver master does not understand extended option passing
// or does not want the dictionary
already_read_first = 1;
}
}
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 (already_read_first) {
already_read_first = 0;
} else {
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
@ -390,7 +616,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
if (is_persistent) {
memset(__afl_area_ptr, 0, MAP_SIZE);
memset(__afl_area_ptr, 0, __afl_map_size);
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
@ -513,13 +739,7 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
///// CmpLog instrumentation
void __cmplog_ins_hook1(uint8_t Arg1, uint8_t Arg2) {
return;
}
void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
if (!__afl_cmp_map) return;
@ -534,16 +754,36 @@ void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
// if (!__afl_cmp_map->headers[k].cnt)
// __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
__afl_cmp_map->headers[k].shape = 1;
//__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
__afl_cmp_map->headers[k].shape = 0;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = Arg1;
__afl_cmp_map->log[k][hits].v1 = Arg2;
__afl_cmp_map->log[k][hits].v0 = arg1;
__afl_cmp_map->log[k][hits].v1 = arg2;
}
void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
if (!__afl_cmp_map) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
u32 hits = __afl_cmp_map->headers[k].hits;
__afl_cmp_map->headers[k].hits = hits + 1;
__afl_cmp_map->headers[k].shape = 1;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = arg1;
__afl_cmp_map->log[k][hits].v1 = arg2;
}
void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
if (!__afl_cmp_map) return;
@ -559,12 +799,12 @@ void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
__afl_cmp_map->headers[k].shape = 3;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = Arg1;
__afl_cmp_map->log[k][hits].v1 = Arg2;
__afl_cmp_map->log[k][hits].v0 = arg1;
__afl_cmp_map->log[k][hits].v1 = arg2;
}
void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
if (!__afl_cmp_map) return;
@ -580,44 +820,44 @@ void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
__afl_cmp_map->headers[k].shape = 7;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = Arg1;
__afl_cmp_map->log[k][hits].v1 = Arg2;
__afl_cmp_map->log[k][hits].v0 = arg1;
__afl_cmp_map->log[k][hits].v1 = arg2;
}
#if defined(__APPLE__)
#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_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
#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)
void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
__attribute__((alias("__cmplog_ins_hook1")));
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2)
void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
__attribute__((alias("__cmplog_ins_hook2")));
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2)
void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
__attribute__((alias("__cmplog_ins_hook4")));
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2)
void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
__attribute__((alias("__cmplog_ins_hook8")));
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2)
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)
void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
__attribute__((alias("__cmplog_ins_hook2")));
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2)
void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
__attribute__((alias("__cmplog_ins_hook4")));
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2)
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) {
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
for (uint64_t i = 0; i < Cases[0]; i++) {
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = (uintptr_t)__builtin_return_address(0) + i;
k = (k >> 4) ^ (k << 8);
@ -631,8 +871,8 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
__afl_cmp_map->headers[k].shape = 7;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = Val;
__afl_cmp_map->log[k][hits].v1 = Cases[i + 2];
__afl_cmp_map->log[k][hits].v0 = val;
__afl_cmp_map->log[k][hits].v1 = cases[i + 2];
}

View File

@ -38,15 +38,16 @@
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
using namespace llvm;
@ -58,22 +59,7 @@ class CmpLogInstructions : public ModulePass {
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);
}
}
initWhitelist();
}
@ -91,8 +77,7 @@ class CmpLogInstructions : public ModulePass {
}
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
int be_quiet = 0;
private:
bool hookInstrs(Module &M);
@ -185,119 +170,10 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
if (!isInWhitelist(&F)) continue;
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;
@ -360,11 +236,20 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
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;
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;
}

View File

@ -38,15 +38,16 @@
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
using namespace llvm;
@ -58,22 +59,7 @@ class CmpLogRoutines : public ModulePass {
static char ID;
CmpLogRoutines() : 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);
}
}
initWhitelist();
}
@ -91,8 +77,7 @@ class CmpLogRoutines : public ModulePass {
}
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
int be_quiet = 0;
private:
bool hookRtns(Module &M);
@ -132,119 +117,10 @@ bool CmpLogRoutines::hookRtns(Module &M) {
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
if (!isInWhitelist(&F)) continue;
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) {
CallInst *callInst = nullptr;

View File

@ -25,7 +25,6 @@
#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"
@ -38,15 +37,16 @@
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
using namespace llvm;
@ -58,22 +58,7 @@ class CompareTransform : public ModulePass {
static char ID;
CompareTransform() : 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);
}
}
initWhitelist();
}
@ -91,8 +76,7 @@ class CompareTransform : public ModulePass {
}
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
int be_quiet = 0;
private:
bool transformCmps(Module &M, const bool processStrcmp,
@ -112,11 +96,12 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
const bool processStrcasecmp,
const bool processStrncasecmp) {
std::vector<CallInst *> calls;
LLVMContext & C = M.getContext();
IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
DenseMap<Value *, std::string *> valueMap;
std::vector<CallInst *> calls;
LLVMContext & C = M.getContext();
IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
#if LLVM_VERSION_MAJOR < 9
Constant *
@ -139,119 +124,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
* strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
for (auto &F : M) {
if (!isInWhitelist(&F)) continue;
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) {
CallInst *callInst = nullptr;
@ -263,6 +139,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
bool isStrncmp = processStrncmp;
bool isStrcasecmp = processStrcasecmp;
bool isStrncasecmp = processStrncasecmp;
bool isIntMemcpy = true;
bool indirect = false;
Function *Callee = callInst->getCalledFunction();
if (!Callee) continue;
@ -273,9 +151,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
isStrncmp &= !FuncName.compare(StringRef("strncmp"));
isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp"));
isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp"));
isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp)
!isStrncasecmp && !isIntMemcpy)
continue;
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
@ -309,7 +188,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
FT->getParamType(2)->isIntegerTy();
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp)
!isStrncasecmp && !isIntMemcpy)
continue;
/* is a str{n,}{case,}cmp/memcmp, check if we have
@ -322,8 +201,107 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
if (isIntMemcpy && HasStr2) {
valueMap[Str1P] = new std::string(Str2.str());
// fprintf(stderr, "saved %s for %p\n", Str2.str().c_str(), Str1P);
continue;
}
// not literal? maybe global or local variable
if (!(HasStr1 || HasStr2)) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString();
valueMap[Str2P] = new std::string(Str2.str());
fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
}
}
}
}
if (!HasStr2) {
auto *Ptr = dyn_cast<ConstantExpr>(Str1P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString();
valueMap[Str1P] = new std::string(Str1.str());
// fprintf(stderr, "glo1 %s\n", Str1.str().c_str());
}
}
}
}
} else if (isIntMemcpy) {
valueMap[Str1P] = new std::string(Str2.str());
// fprintf(stderr, "saved\n");
}
if ((HasStr1 || HasStr2)) indirect = true;
}
if (isIntMemcpy) continue;
if (!(HasStr1 || HasStr2)) {
// do we have a saved local variable initialization?
std::string *val = valueMap[Str1P];
if (val && !val->empty()) {
Str1 = StringRef(*val);
HasStr1 = true;
indirect = true;
// fprintf(stderr, "loaded1 %s\n", Str1.str().c_str());
} else {
val = valueMap[Str2P];
if (val && !val->empty()) {
Str2 = StringRef(*val);
HasStr2 = true;
indirect = true;
// fprintf(stderr, "loaded2 %s\n", Str2.str().c_str());
}
}
}
/* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) continue;
if (!(HasStr1 || HasStr2)) continue;
if (isMemcmp || isStrncmp || isStrncasecmp) {
@ -334,9 +312,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
if (!ilen) continue;
/* final precaution: if size of compare is larger than constant
* string skip it*/
uint64_t literalLength =
HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P);
if (literalLength < ilen->getZExtValue()) continue;
uint64_t literalLength = HasStr1 ? Str1.size() : Str2.size();
if (literalLength + 1 < ilen->getZExtValue()) continue;
}
@ -363,9 +340,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
std::string TmpConstStr;
Value * VarStr;
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
getConstantStringInfo(Str2P, Str2);
uint64_t constLen, sizedLen;
bool isMemcmp =
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
uint64_t constLen, sizedLen;
bool isMemcmp =
!callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
bool isSizedcmp = isMemcmp ||
!callInst->getCalledFunction()->getName().compare(
@ -389,17 +366,40 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
if (!(HasStr1 || HasStr2)) {
// do we have a saved local or global variable initialization?
std::string *val = valueMap[Str1P];
if (val && !val->empty()) {
Str1 = StringRef(*val);
HasStr1 = true;
} else {
val = valueMap[Str2P];
if (val && !val->empty()) {
Str2 = StringRef(*val);
HasStr2 = true;
}
}
}
if (HasStr1) {
TmpConstStr = Str1.str();
VarStr = Str2P;
constLen = isMemcmp ? sizedLen : GetStringLength(Str1P);
constLen = isMemcmp ? sizedLen : TmpConstStr.length();
} else {
TmpConstStr = Str2.str();
VarStr = Str1P;
constLen = isMemcmp ? sizedLen : GetStringLength(Str2P);
constLen = isMemcmp ? sizedLen : TmpConstStr.length();
}
@ -407,9 +407,14 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
* the StringRef (in comparison to std::string a StringRef has built-in
* runtime bounds checking, which makes debugging easier) */
TmpConstStr.append("\0", 1);
if (!sizedLen) constLen++;
ConstStr = StringRef(TmpConstStr);
if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; }
// fprintf(stderr, "issized: %d, const > sized ? %u > %u\n", isSizedcmp,
// constLen, sizedLen);
if (isSizedcmp && constLen > sizedLen && sizedLen) constLen = sizedLen;
if (constLen > TmpConstStr.length()) constLen = TmpConstStr.length();
if (!constLen) constLen = TmpConstStr.length();
if (!constLen) continue;
if (!be_quiet)
errs() << callInst->getCalledFunction()->getName() << ": len " << constLen
@ -500,7 +505,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
bool CompareTransform::runOnModule(Module &M) {
if (isatty(2) && getenv("AFL_QUIET") == NULL)
if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, "
"extended by heiko@hexco.de\n";
else

View File

@ -27,7 +27,6 @@
#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"
@ -37,15 +36,16 @@
#include "llvm/IR/IRBuilder.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
using namespace llvm;
#include "afl-llvm-common.h"
namespace {
@ -55,40 +55,7 @@ class SplitComparesTransform : public ModulePass {
static char ID;
SplitComparesTransform() : 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);
}
}
}
static bool isBlacklisted(const Function *F) {
static const char *Blacklist[] = {
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
initWhitelist();
}
@ -105,8 +72,7 @@ class SplitComparesTransform : public ModulePass {
}
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
int be_quiet = 0;
private:
int enableFPSplit;
@ -136,121 +102,10 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
* all integer comparisons with >= and <= predicates to the icomps vector */
for (auto &F : M) {
if (isBlacklisted(&F)) continue;
if (!isInWhitelist(&F)) continue;
for (auto &BB : F) {
if (!myWhitelist.empty()) {
bool instrumentBlock = false;
BasicBlock::iterator IP = BB.getFirstInsertionPt();
/* 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;
@ -318,10 +173,18 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
CmpInst::Predicate new_pred;
switch (pred) {
case CmpInst::ICMP_UGE: new_pred = CmpInst::ICMP_UGT; break;
case CmpInst::ICMP_SGE: new_pred = CmpInst::ICMP_SGT; break;
case CmpInst::ICMP_ULE: new_pred = CmpInst::ICMP_ULT; break;
case CmpInst::ICMP_SLE: new_pred = CmpInst::ICMP_SLT; break;
case CmpInst::ICMP_UGE:
new_pred = CmpInst::ICMP_UGT;
break;
case CmpInst::ICMP_SGE:
new_pred = CmpInst::ICMP_SGT;
break;
case CmpInst::ICMP_ULE:
new_pred = CmpInst::ICMP_ULT;
break;
case CmpInst::ICMP_SLE:
new_pred = CmpInst::ICMP_SLT;
break;
default: // keep the compiler happy
continue;
@ -384,10 +247,18 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
CmpInst::Predicate new_pred;
switch (pred) {
case CmpInst::FCMP_UGE: new_pred = CmpInst::FCMP_UGT; break;
case CmpInst::FCMP_OGE: new_pred = CmpInst::FCMP_OGT; break;
case CmpInst::FCMP_ULE: new_pred = CmpInst::FCMP_ULT; break;
case CmpInst::FCMP_OLE: new_pred = CmpInst::FCMP_OLT; break;
case CmpInst::FCMP_UGE:
new_pred = CmpInst::FCMP_UGT;
break;
case CmpInst::FCMP_OGE:
new_pred = CmpInst::FCMP_OGT;
break;
case CmpInst::FCMP_ULE:
new_pred = CmpInst::FCMP_ULT;
break;
case CmpInst::FCMP_OLE:
new_pred = CmpInst::FCMP_OLT;
break;
default: // keep the compiler happy
continue;
@ -855,7 +726,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
icmp_exponent_result =
BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
break;
default: continue;
default:
continue;
}
@ -958,7 +830,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
icmp_fraction_result =
BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0);
break;
default: continue;
default:
continue;
}
@ -1004,7 +877,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
PN->addIncoming(icmp_exponent_result, signequal_bb);
PN->addIncoming(icmp_fraction_result, middle_bb);
break;
default: continue;
default:
continue;
}

View File

@ -26,7 +26,6 @@
#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"
@ -40,15 +39,16 @@
#include "llvm/IR/IRBuilder.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
using namespace llvm;
@ -60,40 +60,7 @@ class SplitSwitchesTransform : public ModulePass {
static char ID;
SplitSwitchesTransform() : 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);
}
}
}
static bool isBlacklisted(const Function *F) {
static const char *Blacklist[] = {
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
};
for (auto const &BlacklistFunc : Blacklist) {
if (F->getName().startswith(BlacklistFunc)) { return true; }
}
return false;
initWhitelist();
}
@ -125,8 +92,7 @@ class SplitSwitchesTransform : public ModulePass {
typedef std::vector<CaseExpr> CaseVector;
protected:
std::list<std::string> myWhitelist;
int be_quiet = 0;
int be_quiet = 0;
private:
bool splitSwitches(Module &M);
@ -346,122 +312,12 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
* all switches to switches vector for later processing */
for (auto &F : M) {
if (isBlacklisted(&F)) continue;
if (!isInWhitelist(&F)) continue;
for (auto &BB : F) {
SwitchInst *switchInst = nullptr;
if (!myWhitelist.empty()) {
bool instrumentBlock = false;
BasicBlock::iterator IP = BB.getFirstInsertionPt();
/* 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;
}
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
if (switchInst->getNumCases() < 1) continue;
@ -561,7 +417,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
bool SplitSwitchesTransform::runOnModule(Module &M) {
if (isatty(2) && getenv("AFL_QUIET") == NULL)
if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n";
else
be_quiet = 1;

View File

@ -52,6 +52,6 @@ ${compiler_prefix}${CC} -shared -o libdemo.so demo-so.c -w -g
echo "[+] Building afl-fuzz for Android"
# build afl-fuzz
cd ..
${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-misc.c src/afl-fuzz-extras.c src/afl-fuzz-queue.c src/afl-fuzz-one.c src/afl-fuzz-python.c src/afl-fuzz-stats.c src/afl-fuzz-init.c src/afl-fuzz.c src/afl-fuzz-bitmap.c src/afl-fuzz-run.c src/afl-fuzz-state.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o qbdi_mode/afl-fuzz -ldl -w
${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-*.c src/afl-fuzz.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o qbdi_mode/afl-fuzz -ldl -w
echo "[+] All done. Enjoy!"

View File

@ -29,7 +29,9 @@ int target_func(char *buf, int size) {
}
break;
default: puts("default action"); break;
default:
puts("default action");
break;
}

View File

@ -11,7 +11,7 @@
#include <dlfcn.h>
#ifdef __ANDROID__
#include "../include/android-ashmem.h"
#include "../include/android-ashmem.h"
#endif
#include <sys/ipc.h>
@ -23,15 +23,15 @@
/* NeverZero */
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
#define INC_AFL_AREA(loc) \
asm volatile( \
"incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \
: /* no out */ \
: "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax")
#define INC_AFL_AREA(loc) \
asm volatile( \
"incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \
: /* no out */ \
: "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax")
#else
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
#endif
using namespace QBDI;

View File

@ -46,8 +46,8 @@ You can also compile statically-linked binaries by setting STATIC=1. This
can be useful when compiling QEMU on a different system than the one you're
planning to run the fuzzer on and is most often used with the HOST variable.
Note: when targetting the i386 architecture, on some bianries the forkserver
handshake may fail due to the lack of reversed memory. Fix it with
Note: when targetting the i386 architecture, on some binaries the forkserver
handshake may fail due to the lack of reserved memory. Fix it with
export QEMU_RESERVED_VA=0x1000000

View File

@ -23,8 +23,10 @@ in 2.2 and 2.3) have to be set.
This address (as well as the RET address, see below) has to be defined in
hexadecimal with the 0x prefix or as a decimal value.
If the target is compiled with position independant code (PIE/PIC), you must
add 0x4000000000 to that address, because qemu loads to this base address.
*Note:* If the target is compiled with position independant code (PIE/PIC)
qemu loads these to a specific base address.
For 64 bit you have to add 0x4000000000 (9 zeroes) and for 32 bit 0x40000000
(7 zeroes) to the address.
On strange setups the base address set by QEMU for PIE executable may change,
you can check it printing the process map using
`AFL_QEMU_DEBUG_MAPS=1 afl-qemu-trace TARGET-BINARY`
@ -32,7 +34,7 @@ you can check it printing the process map using
If this address is not valid, afl-fuzz will error during startup with the
message that the forkserver was not found.
### 2.2) the RET address
### 2.2) The RET address
The RET address is the last instruction of the persistent loop.
The emulator will emit a jump to START when translating the instruction at RET.
@ -46,7 +48,7 @@ patch the return address (on stack or in the link register) to return to START
It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to
be set if the target is position independant.
### 2.3) the OFFSET
### 2.3) The OFFSET
This option is valid only for x86/x86_64 only, arm/aarch64 do not save the
return address on stack.
@ -72,7 +74,7 @@ Now to get this value right here some help:
8. again print the ESP value
9. calculate the difference between the two values - and this is the offset
### 2.4) resetting the register state
### 2.4) Resetting the register state
It is very, very likely you need to restore the general purpose registers state
when starting a new loop. Because of this you 99% of the time should set

View File

@ -63,7 +63,7 @@ if [ ! -f "../afl-showmap" ]; then
fi
PREREQ_NOTFOUND=
for i in libtool wget python automake autoconf sha384sum bison flex iconv patch pkg-config; do
for i in libtool wget automake autoconf sha384sum bison flex iconv patch pkg-config; do
T=`command -v "$i" 2>/dev/null`
@ -76,6 +76,14 @@ for i in libtool wget python automake autoconf sha384sum bison flex iconv patch
done
PYTHONBIN=`command -v python3 || command -v python || command -v python2`
if [ "$PYTHONBIN" = "" ]; then
echo "[-] Error: 'python' not found, please install using 'sudo apt install python3'."
PREREQ_NOTFOUND=1
fi
if [ ! -d "/usr/include/glib-2.0/" -a ! -d "/usr/local/include/glib-2.0/" ]; then
echo "[-] Error: devel version of 'glib2' not found, please install first."
@ -83,6 +91,13 @@ if [ ! -d "/usr/include/glib-2.0/" -a ! -d "/usr/local/include/glib-2.0/" ]; the
fi
if [ ! -d "/usr/include/pixman-1/" -a ! -d "/usr/local/include/pixman-1/" ]; then
echo "[-] Error: devel version of 'pixman-1' not found, please install first."
PREREQ_NOTFOUND=1
fi
if echo "$CC" | grep -qF /afl-; then
echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
@ -156,6 +171,8 @@ fi
cd qemu-$VERSION || exit 1
echo Building for CPU target $CPU_TARGET
echo "[*] Applying patches..."
patch -p1 <../patches/elfload.diff || exit 1
@ -181,6 +198,7 @@ echo "[+] Patching done."
if [ "$STATIC" = "1" ]; then
echo Building STATIC binary
./configure --extra-cflags="-O3 -ggdb -DAFL_QEMU_STATIC_BUILD=1" \
--disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \
--disable-gcrypt --disable-debug-info --disable-debug-tcg --disable-tcg-interpreter \
@ -192,16 +210,17 @@ if [ "$STATIC" = "1" ]; then
--disable-libusb --disable-usb-redir --disable-vde --disable-vhost-net --disable-virglrenderer \
--disable-virtfs --disable-vnc --disable-vte --disable-xen --disable-xen-pci-passthrough --disable-xfsctl \
--enable-linux-user --disable-system --disable-blobs --disable-tools --enable-capstone=internal \
--target-list="${CPU_TARGET}-linux-user" --static --disable-pie --cross-prefix=$CROSS_PREFIX || exit 1
--target-list="${CPU_TARGET}-linux-user" --static --disable-pie --cross-prefix=$CROSS_PREFIX --python="$PYTHONBIN" \
|| exit 1
else
# --enable-pie seems to give a couple of exec's a second performance
# improvement, much to my surprise. Not sure how universal this is..
./configure --disable-system \
--enable-linux-user --disable-gtk --disable-sdl --disable-vnc --enable-capstone=internal \
--target-list="${CPU_TARGET}-linux-user" --enable-pie $CROSS_PREFIX || exit 1
--target-list="${CPU_TARGET}-linux-user" --enable-pie $CROSS_PREFIX --python="$PYTHONBIN" || exit 1
fi
@ -230,10 +249,12 @@ if [ "$ORIG_CPU_TARGET" = "" ]; then
make >/dev/null || exit 1
gcc test-instr.c -o test-instr || exit 1
cc test-instr.c -o test-instr || exit 1
unset AFL_INST_RATIO
export ASAN_OPTIONS=detect_leaks=0
echo "[*] Comparing two afl-showmap -Q outputs..."
echo 0 | ./afl-showmap -m none -Q -q -o .test-instr0 ./test-instr || exit 1
echo 1 | ./afl-showmap -m none -Q -q -o .test-instr1 ./test-instr || exit 1
@ -267,6 +288,7 @@ echo "[+] Building libcompcov ..."
make -C libcompcov && echo "[+] libcompcov ready"
echo "[+] Building unsigaction ..."
make -C unsigaction && echo "[+] unsigaction ready"
echo "[+] All done for qemu_mode, enjoy!"
exit 0

View File

@ -51,9 +51,11 @@ int main() {
switch (z) {
case 0xBEEF: break;
case 0xBEEF:
break;
default: return 4;
default:
return 4;
}

View File

@ -20,7 +20,7 @@
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#include <stdio.h>
@ -36,7 +36,7 @@
#include "pmparser.h"
#ifndef __linux__
#error "Sorry, this library is Linux-specific for now!"
#error "Sorry, this library is Linux-specific for now!"
#endif /* !__linux__ */
/* Change this value to tune the compare coverage */
@ -166,7 +166,7 @@ static void __compcov_trace(u64 cur_loc, const u8 *v0, const u8 *v1, size_t n) {
if (debug_fd != 1) {
char debugbuf[4096];
snprintf(debugbuf, sizeof(debugbuf), "0x%llx %s %s %lu\n", cur_loc,
snprintf(debugbuf, sizeof(debugbuf), "0x%llx %s %s %zu\n", cur_loc,
v0 == NULL ? "(null)" : (char *)v0,
v1 == NULL ? "(null)" : (char *)v1, n);
write(debug_fd, debugbuf, strlen(debugbuf));

View File

@ -40,27 +40,27 @@
#define PERSISTENT_DEFAULT_MAX_CNT 1000
#ifdef CPU_NB_REGS
#define AFL_REGS_NUM CPU_NB_REGS
#define AFL_REGS_NUM CPU_NB_REGS
#elif TARGET_ARM
#define AFL_REGS_NUM 32
#define AFL_REGS_NUM 32
#elif TARGET_AARCH64
#define AFL_REGS_NUM 32
#define AFL_REGS_NUM 32
#else
#define AFL_REGS_NUM 100
#define AFL_REGS_NUM 100
#endif
/* NeverZero */
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
#define INC_AFL_AREA(loc) \
asm volatile( \
"incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \
: /* no out */ \
: "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax")
#define INC_AFL_AREA(loc) \
asm volatile( \
"incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \
: /* no out */ \
: "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax")
#else
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
#endif
typedef void (*afl_persistent_hook_fn)(uint64_t *regs, uint64_t guest_base);

View File

@ -35,7 +35,7 @@
#include "afl-qemu-common.h"
#ifndef AFL_QEMU_STATIC_BUILD
#include <dlfcn.h>
#include <dlfcn.h>
#endif
/***************************
@ -123,12 +123,11 @@ struct afl_chain {
/* Some forward decls: */
TranslationBlock *tb_htable_lookup(CPUState *, target_ulong, target_ulong,
uint32_t, uint32_t);
static inline TranslationBlock *tb_find(CPUState *, TranslationBlock *, int,
uint32_t);
static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next);
int open_self_maps(void *cpu_env, int fd);
/*************************
* ACTUAL IMPLEMENTATION *
@ -275,30 +274,17 @@ void afl_setup(void) {
}
static void print_mappings(void) {
u8 buf[MAX_LINE];
FILE *f = fopen("/proc/self/maps", "r");
if (!f) return;
while (fgets(buf, MAX_LINE, f))
printf("%s", buf);
fclose(f);
}
/* Fork server logic, invoked once we hit _start. */
void afl_forkserver(CPUState *cpu) {
static unsigned char tmp[4];
u32 map_size = 0;
unsigned char tmp[4] = {0};
if (forkserver_installed == 1) return;
forkserver_installed = 1;
if (getenv("AFL_QEMU_DEBUG_MAPS")) print_mappings();
if (getenv("AFL_QEMU_DEBUG_MAPS")) open_self_maps(cpu->env_ptr, 0);
// if (!afl_area_ptr) return; // not necessary because of fixed dummy buffer
@ -306,6 +292,15 @@ void afl_forkserver(CPUState *cpu) {
int t_fd[2];
u8 child_stopped = 0;
// if in the future qemu has non-collding coverage then switch MAP_SIZE
// with the max ID value
if (MAP_SIZE <= 0x800000) {
map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
memcpy(tmp, &map_size, 4);
}
/* Tell the parent that we're alive. If the parent doesn't want
to talk, assume that we're not running in forkserver mode. */

View File

@ -35,10 +35,10 @@
#include "tcg.h"
#include "tcg-op.h"
#if TCG_TARGET_LONG_BITS == 64
#define _DEFAULT_MO MO_64
#if TCG_TARGET_REG_BITS == 64
#define _DEFAULT_MO MO_64
#else
#define _DEFAULT_MO MO_32
#define _DEFAULT_MO MO_32
#endif
static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
@ -53,12 +53,22 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
TCGv cur_loc_v = tcg_const_tl(cur_loc);
switch (ot) {
switch (ot & MO_SIZE) {
case MO_64: gen_helper_afl_cmplog_64(cur_loc_v, arg1, arg2); break;
case MO_32: gen_helper_afl_cmplog_32(cur_loc_v, arg1, arg2); break;
case MO_16: gen_helper_afl_cmplog_16(cur_loc_v, arg1, arg2); break;
default: break;
case MO_64:
gen_helper_afl_cmplog_64(cur_loc_v, arg1, arg2);
break;
case MO_32:
gen_helper_afl_cmplog_32(cur_loc_v, arg1, arg2);
break;
case MO_16:
gen_helper_afl_cmplog_16(cur_loc_v, arg1, arg2);
break;
case MO_8:
gen_helper_afl_cmplog_8(cur_loc_v, arg1, arg2);
break;
default:
break;
}
@ -75,12 +85,19 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
if (cur_loc >= afl_inst_rms) return;
switch (ot) {
switch (ot & MO_SIZE) {
case MO_64: gen_helper_afl_compcov_64(cur_loc_v, arg1, arg2); break;
case MO_32: gen_helper_afl_compcov_32(cur_loc_v, arg1, arg2); break;
case MO_16: gen_helper_afl_compcov_16(cur_loc_v, arg1, arg2); break;
default: break;
case MO_64:
gen_helper_afl_compcov_64(cur_loc_v, arg1, arg2);
break;
case MO_32:
gen_helper_afl_compcov_32(cur_loc_v, arg1, arg2);
break;
case MO_16:
gen_helper_afl_compcov_16(cur_loc_v, arg1, arg2);
break;
default:
break;
}

View File

@ -107,18 +107,39 @@ void HELPER(afl_compcov_64)(target_ulong cur_loc, target_ulong arg1,
}
void HELPER(afl_cmplog_8)(target_ulong cur_loc, target_ulong arg1,
target_ulong arg2) {
register uintptr_t k = (uintptr_t)cur_loc;
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
u32 hits = __afl_cmp_map->headers[k].hits;
__afl_cmp_map->headers[k].hits = hits + 1;
// if (!__afl_cmp_map->headers[k].cnt)
// __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
__afl_cmp_map->headers[k].shape = 0;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = arg1;
__afl_cmp_map->log[k][hits].v1 = arg2;
}
void HELPER(afl_cmplog_16)(target_ulong cur_loc, target_ulong arg1,
target_ulong arg2) {
register uintptr_t k = (uintptr_t)cur_loc;
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
u32 hits = __afl_cmp_map->headers[k].hits;
__afl_cmp_map->headers[k].hits = hits + 1;
// if (!__afl_cmp_map->headers[k].cnt)
// __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
__afl_cmp_map->headers[k].shape = 1;
//__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
hits &= CMP_MAP_H - 1;
__afl_cmp_map->log[k][hits].v0 = arg1;
@ -131,6 +152,8 @@ void HELPER(afl_cmplog_32)(target_ulong cur_loc, target_ulong arg1,
register uintptr_t k = (uintptr_t)cur_loc;
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
u32 hits = __afl_cmp_map->headers[k].hits;
__afl_cmp_map->headers[k].hits = hits + 1;
@ -147,6 +170,8 @@ void HELPER(afl_cmplog_64)(target_ulong cur_loc, target_ulong arg1,
register uintptr_t k = (uintptr_t)cur_loc;
__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
u32 hits = __afl_cmp_map->headers[k].hits;
__afl_cmp_map->headers[k].hits = hits + 1;

View File

@ -1,5 +1,5 @@
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b13a170e..4af79175 100644
index b13a170e..3f5cc902 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -111,6 +111,9 @@
@ -43,7 +43,17 @@ index b13a170e..4af79175 100644
ts = (TaskState *)cpu->opaque;
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
@@ -7324,10 +7328,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
@@ -6554,7 +6558,8 @@ static int open_self_cmdline(void *cpu_env, int fd)
return 0;
}
-static int open_self_maps(void *cpu_env, int fd)
+int open_self_maps(void *cpu_env, int fd);
+int open_self_maps(void *cpu_env, int fd)
{
CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
TaskState *ts = cpu->opaque;
@@ -7324,10 +7329,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
@ -59,7 +69,7 @@ index b13a170e..4af79175 100644
}
#endif
#ifdef TARGET_NR_alarm /* not on alpha */
@@ -10529,7 +10535,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
@@ -10529,7 +10536,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return TARGET_PAGE_SIZE;
#endif
case TARGET_NR_gettid:
@ -68,7 +78,7 @@ index b13a170e..4af79175 100644
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
#if TARGET_ABI_BITS == 32
@@ -10813,8 +10819,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
@@ -10813,8 +10820,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
case TARGET_NR_tgkill:

View File

@ -2,7 +2,7 @@ diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
index 1bd39d13..81ef3973 100644
--- a/accel/tcg/tcg-runtime.h
+++ b/accel/tcg/tcg-runtime.h
@@ -260,3 +260,13 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -260,3 +260,14 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@ -12,6 +12,7 @@ index 1bd39d13..81ef3973 100644
+DEF_HELPER_FLAGS_3(afl_compcov_16, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_compcov_32, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_compcov_64, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_cmplog_8, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_cmplog_16, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_cmplog_32, TCG_CALL_NO_RWG, void, tl, tl, tl)
+DEF_HELPER_FLAGS_3(afl_cmplog_64, TCG_CALL_NO_RWG, void, tl, tl, tl)

View File

@ -1,34 +0,0 @@
#
# american fuzzy lop++ - unsigaction
# --------------------------------
#
# Written by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2019-2020 Andrea Fioraldi. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
ifndef AFL_NO_X86
all: lib_i386 lib_amd64
lib_i386:
@$(CC) -m32 -fPIC -shared unsigaction.c -o unsigaction32.so 2>/dev/null ; if [ "$$?" = "0" ]; then echo "unsigaction32 build success"; else echo "unsigaction32 build failure (that's fine)"; fi
lib_amd64:
$(CC) -fPIC -shared unsigaction.c -o unsigaction64.so
clean:
rm -f unsigaction32.so unsigaction64.so
else
all:
@echo "[!] Note: skipping compilation of unsigaction (AFL_NO_X86 set)."
endif

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